Bug #110789 OpenAsync throws unhandled exception from thread pool
Submitted: 24 Apr 18:17 Modified: 7 Jun 14:59
Reporter: Bradley Grainger (OCA) Email Updates:
Status: Verified Impact on me:
None 
Category:Connector / NET Severity:S2 (Serious)
Version:8.0.33 OS:Windows (10)
Assigned to: CPU Architecture:Any

[24 Apr 18:17] Bradley Grainger
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}");
}
[7 Jun 14:59] MySQL Verification Team
Hello Bradley Grainger,

Thank you for the bug report.
Verified as described.

Regards,
Ashwini Patil