Open coderb opened 3 years ago
Hi @coderb
Thanks for opening up this issue. This is a known design issue as driver internals are still synchronously designed and not everything supports awaiting yet. It's also a very heavy activity and requires major rework in the driver.
We'll have to see if this receives more community interest and shall be prioritized accordingly.
Would it be better to implement OpenAsync()
as return Task.Run(connection.Open)
in the interim which would unblock the caller thread? This way users can code to the async api without workarounds and the application code wouldn't need to be updated when the library is fully async.
@coderb I'm personally not a fan of having async methods needlessly do that, since it just adds overhead for the common case. 100% agree that OpenAsync() should be implemented with as much asynchrony as possible, though.
We'll have to see if this receives more community interest and shall be prioritized accordingly.
@cheenamalhotra my worry is that this issue is going to be pretty invisible to most unless it causes a major problem. I certainly had assumed that OpenAsync()
was fully asynchronous at this point, but never thought to dig in and check.
Would it be better to implement OpenAsync() as return Task.Run(connection.Open) in the interim which would unblock the caller thread?
This could trigger TP starvation issues, as TP threads synchronously block on connection.Open, and so none are available to execute async callbacks.
We experienced a thread pool starvation issue today with this, while having connection pooling disabled. 28000 treads created for 28000 SQL calls in 12min30s. Hugues process pauses. Reactivating SqlConnection pooling fixes the issue.
1ms threads are created just to initiate the connection.
FYI, we disabled pooling because of a process needing to make a few calls on 2000 distinct databases, with specific connection string for each.
Closing the issue as it is by design. Feel free to comment here or open a new issue.
@JRahnama are you saying it's by-design for OpenAsync to perform synchronous I/O and block the thread? OpenAsync really should never block the thread on I/O.
@roji I mixed this issue with another one I was looking at. Thanks for catching my mistake.
Reopening the issue as it was closed by mistake.
Can we remove the "By Design" label, so this issue could get more attention?
I support this issue as it can remove a little bottleneck specially when we're talking about aspnet core. Due to the fact asptnet core controls multiple requests mainly through Tasks, not Threads, the fact OpenAsync actually runs syncrhonously under the hood makes requests on the same Thread to be queued until each one acquires a Connection from the pool.
Of course, if the connections are already created, this is not an issue at all, but let's suppose the minimum pool is 1, while the maximum is 100 (default config), the api is almost idle and a sudden heavy load reaches the API. In this scenario, multiple connection we'll be created, causing an undesired enqueing of OpenAsync calls on the Thread, even though SQL Server may easily handle multiple connections being stablished.
A similar issue may happen in any application focused on Tasks, like a custom one to consume a SQS Queue, for example.
please see the stack trace below.
SqlConnection.OpenAsync() has a code path that does synchronous blocking network i/o to the sql server.
my use case is a sql server reboot during a client request. the stack below was called from a u/i thread which subsequently hung the application due to OpenAsync() doing synchronous network i/o rather than awaiting.
(version 2.1.0 netcore)