New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unhandled exception on timerqueue #820
Comments
Also, I think that ObjectDisposedException exception might be a sign of a double-dispose on the socket. For this, maybe applying the safe dispose pattern to then queued timer action instead of directly calling dispose on the socket is the solution. |
I don't think the (I'm finding it rather difficult to read the exception call stacks, though; they seem to be mostly, but not entirely "upside down".) |
I'm suspecting there's a race condition between |
Sorry ab weird stacktraces, this is the best i could do. I think TimerQueue should be more defensive, taking down the whole process is quite severe. I use 2 mechanisms to enforce timeouts:
For some command's I've taken care to have lower session timeout compared to CancellationTokenSource, but for others I know I've missed adding it. Maybe this is the race condition. |
There is definitely a problem if |
Are you able to provide some sample code of what "typical" database access in your code looks like? I've been trying to repro a high-concurrency cancellation race condition but haven't had success so far. |
Ok, Pseudocode is like this: public async Task<IEnumerable<T>> SearchForSomething(CancellationToken? token)
{
var operationTimeout = TimeSpan.FromSeconds(15);
using var cts = new CancellationTokenSource(operationTimeout);
await using var _ = (token ?? CancellationToken.None).Register(cts.Cancel);
using var conn = new MySqlConnection(DatabaseConnectionString);
await conn.OpenAsync(cts.Token);
await using var cmd = conn.CreateCommand();
cmd.CommandText = @"
SET SESSION MAX_EXECUTION_TIME={operationTimeout.Subtract(TimeSpan.FromSeconds(1)).TotalMilliseconds};
(some sql query)";
await using (var reader = await cmd.ExecuteReaderAsync(System.Data.CommandBehavior.SequentialAccess, cts.Token) as MySqlDataReader)
{
while (await reader.ReadAsync(cts.Token))
{
//reder code.
}
}
} Often the command is reused within the same method to manage temporary tables creation/deletion; other times I use transactions. I used to have the same server timeout as the client timeout untill yesterday SET SESSION MAX_EXECUTION_TIME={operationTimeout.TotalMilliseconds}; now, I've subtracted 1s from the operation timeout, to get some determinisms on who enforces timeouts. In a few days, I'll be able to tell if this provided a solution. This is .net core 3.1 against GCP Cloud Mysql, which is 5.7 with almost all default options set. System.AggregateException: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread. (Cannot access a disposed object.
Object name: 'System.Net.Sockets.Socket'.)
---> System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.Socket'.
at System.Net.Sockets.Socket.EndConnect(IAsyncResult asyncResult)
at System.Net.Sockets.Socket.<>c.<ConnectAsync>b__275_0(IAsyncResult iar)
--- End of inner exception stack trace --- I know this does not take the process down, but still, it should be avoided. |
Thanks; I'll try to test something similar later. BTW is using var combinedSource = CancellationTokenSource.CreateLinkedTokenSource(cts.Token, token ?? CancellationToken.None);
// use combinedSource.Token below They're probably pretty similar under-the-hood, but I feel that |
No, i was not aware of CreateLinkedTokenSource. using var cts = CancellationTokenSource.CreateLinkedTokenSource(token);
cts.CancelAfter(TimeSpan.FromSeconds(55)); |
@bgrainger After changing the mysql session timeout to be less then the CancellationTokenSource timeout, i am no longer seeing the timer exception. Though my logs are full of double dispose issues on sockets. |
Most other ADO.NET libraries ignore failure/invalid state in I'll make the same change in MySqlConnector, which will have the side-effect of fixing this bug/race. |
Hi,
I'm running a moderately-high traffic asp.net core 3.1 app that constantly goes down due to unhandled exceptions that appear to come from the TimerQueue.
All code is disposing properly (using and async using), is async and I am extensively trying to enforce timeouts: using CancellationTokens and sometimes using mysql's built-in
set session max_execution_timoeut
.I'm trying to provide some sample stack traces.
Reviewing the TimerQueue code, line 79 invokes the action without protecting against exceptions, which seems to be my case. iirc exceptions on threading times callbacks take down the process.
The text was updated successfully, but these errors were encountered: