Skip to content

SqlConnection fails to reliably keep long-running connection open #25458

@kevcunnane

Description

@kevcunnane

This issue affects applications such as SQL Operations Studio which have long-running connections (e.g. backing a T-SQL Editor) based on the .Net Core stack. On the .Net Full stack, the connection reliably stays open or reports as non-open in the ConnectionState, allowing the application to reopen as needed. However on the .Net Core stack the state is shown as Open but on attempting any command the command will attempt to run for ~60sec, then fail with an error message

A transport-level error has occurred when receiving results from the server. (provider: TCP Provider, error: 35 - An internal exception was caught)

This has a high impact on reliability of tools build on top of .Net Core for SqlClient usage.

Related issue: microsoft/azuredatastudio#870.

**Diagnosis by @saurabh500 **:
Windows impl of SqlClient sets some Keepalive values which Unix stack doesn’t
SqlClient should set the keep alive values.

Original issue details:

  • SQL Operations Studio Version: Feb release & latest from master

Steps to Reproduce:

  • Use a macOS machine, such as the one owned by @twright-msft. Not all machines will work (mine is super-reliable for instance)
  • Run a query against any DB
  • Walk away for 30min
  • Re-run the query

Expected:

  • Query executes 2nd time around

Actual:

  • Executing... spins for ~1minute, then we get an error message in the batch stating
    • Note that even if we could just get a quick failure in a way where we could then close & reopen the connection that'd be OK. It's the lack of reliability plus a long wait that's making this quite bad.

A transport-level error has occurred when receiving results from the server. (provider: TCP Provider, error: 35 - An internal exception was caught)

  • If you are running 2 batches, you may see another message:

Query failed: BeginExecuteReader requires an open and available Connection. The connection's current state is open.

Note that we're actually checking if the connection isn't open but this isn't reliable when it comes to TCP sockets closing. This may well be a driver-side issue, but any fix/workaround we can apply would be good.

Here's our code to close & reopen on issues:

        private void VerifyConnectionOpen(DbConnection connection)
        {
            if (connection == null)
            {
                // Ignore this connection
                return;
            }
 
            if (connection.State != ConnectionState.Open)
            {
                // Note: this will fail and throw to the caller if something goes wrong.
                // This seems the right thing to do but if this causes serviceability issues where stack trace
                // is unexpected, might consider catching and allowing later code to fail. But given we want to get
                // an opened connection for any action using this, it seems OK to handle in this manner
                ClearPool(connection);
                connection.Open();
            }
        }

We can add connection.Close() in this case which might fix issues where connection is in a broken state, but definitely doesn't fix the error all up.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions