Open rrs opened 1 year ago
@rrs thanks for bringing this up. We will investigate this.
I confirm the issue is reproducible with the repro app. The connection pool is single-threaded by design, and a semaphore manages the queue. A possible scenario would be a minor gap that causes a connection enters the pooling queue, while it's about to timeout and the other connection is still waiting for a response from the server. If a task with the timeout owned the main thread it could throw it unless the other task throws the SqlException.
Adding the snapshots for the record:
Bug
When attempting to connect to a remote host that is not available for some specific reasons, and when opening multiple concurrent connections (2 is enough), sometimes an InvalidOperationException is thrown with the suggestion the connection pool is exhausted.
Reproduce
https://github.com/rrs/MicrosoftSqlClientInvalidOperationException
Point to another machine on your network where you can block it, using a firewall rule to block SQL on that port. It will not throw the exception every time. Sometimes you get the 'real' exception which in my case is Access Denied as you would expect. You can change the two tasks to call the QueryAsync (which calls openasync) and change to one of each. This is where it gets a bit hairy. I find on my machine if I do
it will often InvalidOperationException. If I do
it will often InvalidOperationException. If I do
it won't do it at all or if i do
It won't do it at all However in our (nearly) production code which uses just the OpenAsync method it has been caught doing it but just once in quite few weeks of testing.
Expected behavior
The exception should be one of the underlying Microsoft.Data.SqlClient.SqlException that you can see are thrown, or the message should express what is actually going wrong.
Further technical details
Microsoft.Data.SqlClient version: Nuget version 5.1.1 .NET target: .Net 6 SQL Server version: Any Operating system: Windows 11
Additional context
Certain types of connectivity seem to be required to trigger this. We have had this when pulling a network cable and it is most easily reproducible by setting a blocking rule on the sql port on the remote host. (Outbound might work too)
A little bit more background to give some context. We have added some connection durability code to our app that will popup a spinner and say there is a problem, and will keep retrying the operation as long as the exception code is connection based errors. This works very well and in most scenarios is robust. However there are some cases where it throws this exception, seemingly about connection pooling. However as shown in the example project this can be triggered with just 2 simultaneous connections.
The exception I get when it's not an invalid operation exception