sql error when using CancellationToken and cancelling it fast multiple times
See original GitHub issuethis is my code (blazor server):
@inject IDbContextFactory<MyContext> cxf
<button type="button" id="btn1" @onclick="btnClick">Load</button>
private CancellationTokenSource cts;
private CancellationTokenSource prevCts;
private async Task btnClick()
{
if (prevCts is not null) prevCts.Cancel();
cts = new CancellationTokenSource();
prevCts = cts;
using var cx = cxf.CreateDbContext();
var res = await cx.Lunches.ToArrayAsync(cts.Token);
var res1 = await cx.Categories.ToArrayAsync(cts.Token);
var res2 = await cx.Countries.ToArrayAsync(cts.Token);
}
to get the error I’m using js to click the button multiple times instantly:
$('#btn1').click().click().click()
usually 3 clicks is enough to get the error
Error: Microsoft.Data.SqlClient.SqlException (0x80131904): The request failed to run because the batch is aborted, this can be caused by abort signal sent from client, or another request is running in the same session, which makes the session busy.
Operation cancelled by user.
at Microsoft.Data.SqlClient.SqlCommand.<>c.<ExecuteDbDataReaderAsync>b__208_0(Task`1 result)
at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.InitializeReaderAsync(AsyncEnumerator enumerator, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToArrayAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
...
--- End of stack trace from previous location ---
when 3 clicks doesn’t throw the error, with about 15 I can get this error:
Error: System.InvalidOperationException: Operation cancelled by user.
at Microsoft.Data.SqlClient.SqlCommand.<>c.<ExecuteDbDataReaderAsync>b__208_0(Task`1 result)
at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.InitializeReaderAsync(AsyncEnumerator enumerator, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToArrayAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
...
Note when the error doesn’t occur (with 2 clicks always), I would see (in ExpressProfiler) that for the cancelled clicks only 1 db request is made and the last one makes all the requests.
Include provider and version information
EF Core version: 7 Database provider: (e.g. Microsoft.EntityFrameworkCore.SqlServer) Target framework: (e.g. .NET 7.0) Operating system: IDE: Visual Studio 2022 17.4
Issue Analytics
- State:
- Created 9 months ago
- Comments:5 (3 by maintainers)
Top Results From Across the Web
Sql Error when using EF with CancellationToken in Blazor ...
Reason for using Cancellation: I'm cancelling the previous request since the user clicked again really fast on something else, so there's no ...
Read more >Cancelling an async SqlClient operation throws ...
When using a cancellation token to cancel an SqlClient async operation, an SqlException is thrown rather than TaskCanceledException.
Read more >Use cancellation token to cancel execution of multiple ...
The CancellationToken passed in to the action should automatically be cancelled if the client aborts the request.
Read more >How to: Listen for Multiple Cancellation Requests | ...
This example shows how to listen to two cancellation tokens simultaneously so that you can cancel an operation if either token requests it....
Read more >Cancel Query Rollback – SQLServerCentral Forums
I cancelled a long running update statement that was running against a large table and now sql server is rolling back changes.
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
@omuleanu what exactly is the behavior you find problematic above? When you trigger a cancellation token, the operation to which it was given is supposed to throw an OperationCanceledException - since the operation can’t complete. It’s your responsibility to catch that exception and handle appropriately (possibly exiting the button click handler right away).
Now, SqlClient specifically doesn’t throw OperationCanceledException, but instead throws a SqlException (see https://github.com/dotnet/SqlClient/issues/26); but that doesn’t seem to be what you’re complaining about (I admit the InvalidOperationException is even more problematic).
You can certainly do that - swallowing cancellation exceptions and making sure things are sane in the face of concurrent updating - though I’m not sure that makes for an intuitive UI 😃
In any case, am going to go ahead and close this as it seems that everything is working as expected. But feel free to post back here with further questions.