Description:
If MySqlConnection.OpenAsync throws a timeout exception, it's now thrown from a background threadpool thread and cannot be handled by the application. This can crash the whole process.
With MySql.Data 8.0.32.1, the test program prints the following output (and exits successfully)
Caught MySql.Data.MySqlClient.MySqlException in 00:00:02.1639965
OpenAsync finished in 00:00:02.1655379
With MySql.Data 8.0.33, the test program crashes with an unhandled exception:
Unhandled exception. System.AggregateException: One or more errors occurred. (Timeout expired. The timeout period elapsed prior to
completion of the operation or the server is not responding.)
---> MySql.Data.MySqlClient.MySqlException (0x80004005): Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
---> System.TimeoutException: The operation has timed out.
at MySql.Data.Common.StreamCreator.<>c.<GetTcpStreamAsync>b__8_1()
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.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
--- End of inner exception stack trace ---
at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
at System.Threading.TimerQueueTimer.Fire(Boolean isThreadPool)
at System.Threading.TimerQueue.FireNextTimers()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart()
It's expected that OpenAsync will return a Task that eventually becomes faulted, so that the application can "await" it and observe the exception.
How to repeat:
Create a "dotnet new console" program and add the following code:
static async Task Main(string[] args)
{
using var connection = new MySqlConnection("server=www.mysql.com;Connect Timeout=2");
var stopwatch = Stopwatch.StartNew();
try
{
await connection.OpenAsync();
}
catch (Exception ex)
{
Console.WriteLine($"Caught {ex.GetType()} in {stopwatch.Elapsed}");
}
Console.WriteLine($"OpenAsync finished in {stopwatch.Elapsed}");
}