New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SqlClient's connection resiliency adds 10 seconds to database existence checks. Consider exposing a way to override it at runtime #14644

Open
divega opened this Issue Dec 20, 2016 · 0 comments

Comments

Projects
None yet
3 participants
@divega
Copy link
Member

divega commented Dec 20, 2016

This is to follow up on a specific issue a customer created today on EF Core at aspnet/EntityFrameworkCore#7283, but the problem has been brought to our attention before.

Both EF6 and EF Core provide APIs that allow applications to create and initialize databases, check for their existence and modify their schemas. These operations can happen at design time (e.g. when using the migrations feature) or at runtime. Attempting to connect to a database that doesn't exist is part of the normal flow of these operations.

In .NET Framework 4.5.1 SqlClient introduced a connection resiliency feature that performs automatic retries if failures occur during SqlConnection.Open(). Two new settings ConnectRetryCount and ConnectRetryInterval were added to the list of settings recognized in connection strings and a default behavior was adopted so if the first attempt to connect to a database fails a retry will occur after 10 seconds if these settings are not specified. The same feature is now included in the .NET Core version of SqlClient.

With only the default behavior this feature introduces a lag of 10 second for any calling code that attempts to connect to a database that doesn't exist. It also prevents any calling code from implementing its own (potentially more efficient) retry logic correctly. This severely affects customer experience and can potentially affect runtime performance.

Two main approaches have been proposed to mitigate this issue on EF code, but they have severe disadvantages:

  1. Recommend customers to disable SqlClient's connection resiliency altogether by setting ConnectRetryCount=0 when working EF and make sure the feature is disabled any time EF runtime or tooling creates a connection string, or even throw if an attempt is made to use a connection that has the feature enabled. The main disadvantages of this approach are:
  • It is not discoverable for customers and so users will still experience the 10 second lags (or exceptions if we decide to throw) for the default case.
  • It prevents the connection resiliency feature in SqlClient from being available in scenarios in which it could actually have been helpful.
  • EF6 supports older versions of .NET Framework than 4.5.1 and for those versions these settings are not valid. The logic would need to take the executing version of .NET Framework into account.
  1. Store aside a copy of the original connection string so that we can modify it with ConnectRetryCount = 0 and create a separate SqlConnection object to perform existence checks.
  • The main problem with this approach is that both EF Core and EF6 support passing a SqlConnection object to be used in the EF context. It is possible that the password would have already been removed from the ConnectionString in that connection object if it was open before, so in that case the connection string would not contain enough credentials to be able to create a separate functional connection object.

At this point we believe that if SqlConnection exposed a way to programmatically disable connection retries without requiring the modification of the connection string we could modify EF6 and EF Core code to restore the correct behavior and eliminate 10 second lags. We are happy to discuss other options with the SqlClient team.

Also note that this issue applies to both .NET Core and .NET Framework.

cc @ajcvickers

Note on how EF Core implements its own retry logic to check for database existence:

In general, any code that is calling SqlConnection.Open() can leverage contextual knowledge to make connection retries more efficient. E.g.:

  • When EF Core performs existence checks, it will only retry on certain errors if they occur immediately after a database has been created.
  • For a regular existence checks (i.e. those that don't happen immediately after the database has been created) EF Core assumes that immediate failures coming from a database server mean that the database effectively doesn't exist and can avoid any retry logic.

@stephentoub stephentoub added this to the Future milestone Apr 12, 2017

@divega divega changed the title SqlClient's connection resiliency causes performance issues to EF customers. Consider exposing a way to override it at runtime SqlClient's connection resiliency hinders fail-fast health or database existence checks. Consider exposing a way to override it at runtime Jul 31, 2018

@divega divega changed the title SqlClient's connection resiliency hinders fail-fast health or database existence checks. Consider exposing a way to override it at runtime SqlClient's connection resiliency adds 10 seconds to database existence checks. Consider exposing a way to override it at runtime Oct 13, 2018

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