Skip to content

Azure SQL: System.ObjectDisposedException: Cannot access a disposed object on OpenAsync #449

Closed

Description

@PashaPash

Describe the bug

On Azure SQL, after short server unavailability / failover, subsequent call to OpenAsync fails with System.ObjectDisposedException: Cannot access a disposed object.

Stack trace:

Microsoft.Data.SqlClient.SqlException (0x80131904): A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 35 - An internal exception was caught)
 ---> System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.Socket'.
   at System.Net.Sockets.Socket.SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, Int32 optionValue)
   at Microsoft.Data.SqlClient.SNI.SNITCPHandle..ctor(String serverName, Int32 port, Int64 timerExpire, Object callbackObject, Boolean parallel)
   at Microsoft.Data.ProviderBase.DbConnectionPool.CheckPoolBlockingPeriod(Exception e)
   at Microsoft.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
   at Microsoft.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
   at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at Microsoft.Data.ProviderBase.DbConnectionPool.WaitForPendingOpen()

Exception is re-thrown with throw e at CheckPoolBlockingPeriod for Azure SQL connections, so only two first lines seems to be related.
MultiSubnetFailover attribute is not set, so it probably follows non-parallel connect path.

To reproduce

Synthetic repo (based on SNITCPHandle.Connect code +Thread.Sleep to force exact timing): https://github.com/PashaPash/ConnectRace/blob/master/ConnectRace/Program.cs

Unable to clearly reproduce it without manual Thread.Sleeps - seems to happen on Azure only, and during (or immediately after) Azure SQL downtime.

Expected behavior

OpenAsync either fails with real network-related error or connects successfully.

Further technical details

Microsoft.Data.SqlClient version: 1.1.1, with #359 fix applied
.NET target: Core 3.0.3
SQL Server version: Azure SQL, listed as 12.0.2000.8 in SSMS
Operating system: Docker Image mcr.microsoft.com/dotnet/core/aspnet:3.0, running on AKS


Same stack trace reported by @TheDruidsKeeper: #359 (comment)

Activity

  1. cheenamalhotra commented on Feb 26, 2020

    @cheenamalhotra
    Member

    Operating system: Docker Image mcr.microsoft.com/dotnet/core/aspnet:3.0, running on AKS

    This does seem to be related to #359
    Can we close this issue and you can provide additional info in the other issue?

  2. PashaPash commented on Feb 26, 2020

    @PashaPash
    Author

    @cheenamalhotra It seems like a different issue for me.

    #359 was caused by socked disposed by reconnect code not waiting for the OpenAsync to complete and hitting the old (disposed) socket.
    In this case, new socked is disposed before it even leaves SNITCPHandle constructor.

    Stack traces looks similar because of CheckPoolBlockingPeriod. The real stack trace is

    System.ObjectDisposedException: Cannot access a disposed object.
    Object name: 'System.Net.Sockets.Socket'.
       at System.Net.Sockets.Socket.SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, Int32 optionValue)
       at Microsoft.Data.SqlClient.SNI.SNITCPHandle..ctor(String serverName, Int32 port, Int64 timerExpire, Object callbackObject, Boolean parallel)
    

    and it is not the same as in #359:

    Cannot access a disposed object.
    Object name: 'System.Net.Sockets.Socket'.
       at System.Net.Sockets.Socket.SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, Int32 optionValue)
       at System.Net.Sockets.Socket.set_ReceiveTimeout(Int32 value)
       at Microsoft.Data.SqlClient.SNI.SNITCPHandle.Receive(SNIPacket& packet, Int32 timeoutInMilliseconds)
    
  3. PashaPash commented on Feb 26, 2020

    @PashaPash
    Author

    @cheenamalhotra I was able to reproduce it. Here is a sample code: https://github.com/PashaPash/ConnectRace/blob/master/ConnectRace/Program.cs

    It is basically SNITCPHandle.Connect with few Thread.Sleep added to get an exact execution order.

    Conditions seems to be Connect Timeout < real host response timeout + bad luck on simultaneous Dispose / Connect calls.

  4. cheenamalhotra commented on Feb 26, 2020

    @cheenamalhotra
    Member

    Thanks @PashaPash

    I will give it a try soon!

  5. olekdes commented on Sep 29, 2020

    @olekdes

    Hello!
    Do you have any updates on this issue?

    We faced a very similar problem a few days ago.
    Our SQL Server was unavailable for some time. After that, each attemt to establish a connection failed with ObjectDisposedException, until we restarted our application.

    Stack trace:

    Microsoft.Data.SqlClient.SqlException (0x80131904): A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 35 - An internal exception was caught)
     ---> System.ObjectDisposedException: Cannot access a disposed object.
    Object name: 'System.Net.Sockets.Socket'.
       at System.Net.Sockets.Socket.SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, Int32 optionValue)
       at Microsoft.Data.SqlClient.SNI.SNITCPHandle..ctor(String serverName, Int32 port, Int64 timerExpire, Object callbackObject, Boolean parallel)
       at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
       at Microsoft.Data.ProviderBase.DbConnectionPool.WaitForPendingOpen()
    --- End of stack trace from previous location where exception was thrown ---
       at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnectionAsync(Boolean errorsExpected, CancellationToken cancellationToken)
       at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnectionAsync(Boolean errorsExpected, CancellationToken cancellationToken)
       at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenAsync(CancellationToken cancellationToken, Boolean errorsExpected)
       at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
       at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.AsyncEnumerator.InitializeReaderAsync(DbContext _, Boolean result, CancellationToken cancellationToken)
       at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
       at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
    

    Environment:
    We have Core 3.1 application running on Docker Image mcr.microsoft.com/dotnet/core/aspnet:3.1 on AKS.
    We use Microsoft.EntityFrameworkCore.SqlServer 3.1.5 and SQL Server v13

  6. Hoffs commented on Nov 20, 2020

    @Hoffs

    Any news on this? Recently encountered this on EF Core 3.1.7

  7. RCTycooner commented on Mar 24, 2021

    @RCTycooner

    I seem to be having this issue as well. It only happens when running my code from AKS (on linux machines), when doing the exact same thing locally from Visual Studio, no problems.

    I get the error about once per minute. (It's running in a background task, that's pretty much continuously running)

    Microsoft.Data.SqlClient.SqlException (0x80131904): A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 35 - An internal exception was caught) ---> System.ObjectDisposedException: Cannot access a disposed object. Object name: 'System.Net.Sockets.Socket'. at System.Net.Sockets.Socket.SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, Int32 optionValue) at Microsoft.Data.SqlClient.SNI.SNITCPHandle..ctor(String serverName, Int32 port, Int64 timerExpire, Object callbackObject, Boolean parallel) at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction)
    at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
    at Microsoft.Data.SqlClient.TdsParser.Connect(ServerInfo serverInfo, SqlInternalConnectionTds connHandler, Boolean ignoreSniOpenTimeout, Int64 timerExpire, Boolean encrypt, Boolean trustServerCert, Boolean integratedSecurity, Boolean withFailover, SqlAuthenticationMethod authType, SqlAuthenticationProviderManager sqlAuthProviderManager)
    at Microsoft.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean ignoreSniOpenTimeout, TimeoutTimer timeout, Boolean withFailover)
    at Microsoft.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString connectionOptions, SqlCredential credential, TimeoutTimer timeout)
    at Microsoft.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(TimeoutTimer timeout, SqlConnectionString connectionOptions, SqlCredential credential, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance)
    at Microsoft.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString userConnectionOptions, SessionData reconnectSessionData, Boolean applyTransientFaultHandling, String accessToken, DbConnectionPool pool, SqlAuthenticationProviderManager sqlAuthProviderManager)
    at Microsoft.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions) at Microsoft.Data.ProviderBase.DbConnectionFactory.CreateNonPooledConnection(DbConnection owningConnection, DbConnectionPoolGroup poolGroup, DbConnectionOptions userOptions)
    at Microsoft.Data.ProviderBase.DbConnectionFactory.<>c__DisplayClass40_0.b__1(Task1 _) at System.Threading.Tasks.ContinuationResultTaskFromResultTask2.InnerInvoke()
    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
    --- End of stack trace from previous location where exception was thrown ---
    at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) --- End of stack trace from previous location where exception was thrown ---
    at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnectionAsync(Boolean errorsExpected, CancellationToken cancellationToken)
    at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnectionAsync(Boolean errorsExpected, CancellationToken cancellationToken)
    at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenAsync(CancellationToken cancellationToken, Boolean errorsExpected)
    at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
    at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable1.AsyncEnumerator.InitializeReaderAsync(DbContext _, Boolean result, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func4 operation, Func4 verifySucceeded, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable1.AsyncEnumerator.MoveNextAsync()
    at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable1 asyncEnumerable, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable1 asyncEnumerable, CancellationToken cancellationToken) `

    Using Microsoft.EntityFrameworkCore.SqlServer 3.1.11, and connecting to an Azure SQL Server.

  8. cheenamalhotra commented on Mar 26, 2021

    @cheenamalhotra
    Member

    Hi @RCTycooner

    We received update on another thread regarding issues in AKS environments ( #647 (comment)), could you check with Azure Support if this is related to your case too? As I see socket exceptions in your stacktrace, that may be pointing to same issue.

  9. JRahnama commented on Jun 15, 2022

    @JRahnama
    Contributor

    @PashaPash I am closing this issue assuming it was solved regarding the last comment and inactivity. Feel free to reopen or create a new issue.

  10. PaulVrugt commented on Mar 11, 2024

    @PaulVrugt

    @JRahnama we are still running into this in version 5.1.5

    We have no clear reproduction scenario. We have an application serving hundreds of customers. Each customer has their own database. Every few weeks the connection to 1 specific (but random each time) database becomes broken with the following stacktrace:

    stacktraceException opening following connection: 'xxx' A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 35 - An internal exception was caught)", "exceptionDetails": [ { "message": "Cannot access a disposed object.\nObject name: 'System.Net.Sockets.Socket'.", "type": "System.ObjectDisposedException", "raw": "System.ObjectDisposedException: Cannot access a disposed object.\nObject name: 'System.Net.Sockets.Socket'.\n at Microsoft.Data.SqlClient.SNI.SNITCPHandle..ctor(String serverName, Int32 port, Int64 timerExpire, Boolean parallel, SqlConnectionIPAddressPreference ipPreference, String cachedFQDN, SQLDNSInfo& pendingDNSInfo, Boolean tlsFirst, String hostNameInCertificate, String serverCertificateFilename)", "stack_frames": [ { "function": "Microsoft.Data.SqlClient.SNI.SNITCPHandle..ctor(string serverName, int port, long timerExpire, bool parallel, SqlConnectionIPAddressPreference ipPreference, string cachedFQDN, ref SQLDNSInfo pendingDNSInfo, bool tlsFirst, string hostNameInCertificate, string serverCertificateFilename)" } ] }, { "message": "A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 35 - An internal exception was caught)", "type": "Microsoft.Data.SqlClient.SqlException", "raw": "Microsoft.Data.SqlClient.SqlException (0x80131904): A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 35 - An internal exception was caught)\n ---> System.ObjectDisposedException: Cannot access a disposed object.\nObject name: 'System.Net.Sockets.Socket'.\n at Microsoft.Data.SqlClient.SNI.SNITCPHandle..ctor(String serverName, Int32 port, Int64 timerExpire, Boolean parallel, SqlConnectionIPAddressPreference ipPreference, String cachedFQDN, SQLDNSInfo& pendingDNSInfo, Boolean tlsFirst, String hostNameInCertificate, String serverCertificateFilename)\n at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)\n at Microsoft.Data.SqlClient.TdsParser.Connect(ServerInfo serverInfo, SqlInternalConnectionTds connHandler, Boolean ignoreSniOpenTimeout, Int64 timerExpire, SqlConnectionString connectionOptions, Boolean withFailover)\n at Microsoft.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString connectionOptions, SqlCredential credential, TimeoutTimer timeout)\n at Microsoft.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(TimeoutTimer timeout, SqlConnectionString connectionOptions, SqlCredential credential, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance)\n at Microsoft.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString userConnectionOptions, SessionData reconnectSessionData, Boolean applyTransientFaultHandling, String accessToken, DbConnectionPool pool)\n at Microsoft.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)\n at Microsoft.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)\n at Microsoft.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)\n at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)\n at Microsoft.Data.ProviderBase.DbConnectionPool.WaitForPendingOpen()\n--- End of stack trace from previous location ---\n

    In our case the situation resolves itself by clearing some internal caching (unrelated to sql) which causes a burst of queries to all tenants, which (we think?) causes the issue to stop happening for a while

    Edit; I now see there is a 5.2 version, which contains some fixes that might be related (for instance: #1029) We're going to update and see if the issue goes away

    edit2: now we found #2378 I guess we'll wait for this to be fixed before updating

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions