Quantcast
Channel: Entity Framework
Viewing all articles
Browse latest Browse all 10318

Updated Wiki: Connection Resiliency Spec

$
0
0

Background

Applications connecting a database server have always been vulnerable to connection breaks due to back-end failures. However, in a LAN based environment these errors are rare enough that extra logic to handle those failures is not often required. With the rise of cloud based database servers and connections over less reliable networks it is now more common for connection breaks to occur, the same networks can also have much higher latency.

Goals

  • Provide the ability to retry actions on a variety of failures automatically
  • A user should be able to implement their own retry strategies and decide which exceptions should cause a retry and which should not.

Non Goals

  • Fully supporting existing EF applications without changes being made to those applications
    • Resiliency is off by default, although we will try to help people know about it by proving information in transient failure exceptions

Design Meeting Notes

http://entityframework.codeplex.com/wikipage?title=Design%20Meeting%20Notes%20-%20November%208%2c%202012
http://entityframework.codeplex.com/wikipage?title=Design%20Meeting%20Notes%20-%20December%206%2c%202012
http://entityframework.codeplex.com/wikipage?title=Design%20Meeting%20Notes%20-%20January%2024%2c%202013

Implementation

Connection retry is taken care of by an implementation of the IExecutionStrategy interface. Implementations of the IExecutionStrategy will be responsible for accepting an action and, if an exception occurs, determining if a retry is appropriate and retrying if it is. EF will use an IExecutionStrategy each time it executes an action against the database. The IExecutionStrategy interface looks like the following (Async methods omitted):
publicinterface IExecutionStrategy
{
    bool RetriesOnFailure { get; }
    void Execute(Action action);
    TResult Execute<TResult>(Func<TResult> func);
}
The implementations of IExecutionStrategy included in EF make use of two other interfaces:

IRetriableExceptionDetector

Implementations of the IRetriableExceptionDetector are responsible for determining whether or not a given exception is considered transient, and can be retried.
publicinterface IRetriableExceptionDetector
{
    bool ShouldRetryOn(Exception ex);
}

IRetryDelayStrategy

Implementations of the IRetryDelayStrategy will be responsible for determining how long EF should wait before trying again.
publicinterface IRetryDelayStrategy
{
    TimeSpan? GetNextDelay(Exception lastException);
}
There is nothing requiring third party implementations of IExecutionStrategy to use these two interfaces, but they are available to be used if needed. There are instructions on replacing one, or both, of these two interfaces with a default execution strategies later in this page.

Default Implementations

EF will ship with four execution strategies:
  1. NonRetryingExecutionStrategy: this execution strategy does not retry any actions, it is the default for databases other than sql server.
  2. DefaultSqlExecutionStrategy: this execution strategy does not retry at all, however, it will wrap any exceptions that the SqlAzureExceptionDetector considers transient to inform users that they might want to enable connection resiliency.
  3. ExecutionStrategy: this class is suitable as a base class for other execution strategies, or used on its own. It implements retry logic based on a provided IRetriableExceptionDetector and IRetryDelayStrategy
  4. SqlAzureExecutionStrategy: this execution strategy inherits from ExecutionStrategy and will retry on exceptions that are known to be possibly transient when working with SqlAzure. It will use an exponential retry delay strategy, so that the delay gets longer as the number of retries grows.
Note: Execution strategies 2 and 3 are included in the Sql Server provider that ships with EF, which is in the EntityFramework.SqlServer assembly.

Using an Execution Strategy

The main way to use execution strategies is to configure EF so that it will use the given strategy for all actions. In order to do this you need to add a resolver to the DependencyResolver chain that EF will use to find an IExecutionStrategy when it requires one.
There is a default dependency resolver that will ask the provider being used for a default execution strategy, the SqlServer provider that ships with EF will return the DefaultSqlExecutioStrategy described in the section above. Other providers will return whichever strategy they think is appropriate for their database. If no execution strategy is found then EF will use the NonRetryingExecutionStrategy.
To use the SqlAzureExecution strategy then you need to add a class to the same assembly as your DbContext that inherits from SqlAzureDbConfiguration. The SqlAzureDbConfiguration class inherits from DbConfiguration and adds the SqlAzureExecutionStrategy to the resolver chain for you.
If you want to configure EF to use a different IExecutionStrategy, one that you have implemented yourself for example, then you need to create a class that inherits from DbConfiguration and add a dependency resolver to the chain. You will need to implement your own IDependencyResolver.

The following is the implementation of SqlAzureExecutionStrategy, which shows how to create the derived DbConfiguration and add a resolver to the chain:
publicclass SqlAzureDbConfiguration : DbConfiguration
{
    public SqlAzureDbConfiguration()
    {
        AddExecutionStrategy(() => new  SqlAzureExecutionStrategy(), null);
    }

    protectedvoid AddExecutionStrategy(Func<IExecutionStrategy> getExecutionStrategy, string serverName)
    {
        AddDependencyResolver(new SqlExecutionStrategyResolver(getExecutionStrategy, serverName));
    }
}
The other way that you could use an execution policy is to create an instance of the execution policy and use it to execute an action yourself. This might be useful when you do not need to retry for most things, but want to use one for a small number of queries. An example of using the execution strategy this way would be something like this:
var executionStrategy = new SqlAzureExecutionStrategy();
var blogs = executionStrategy.Execute<IEnumerable<Blog>>(GetBlogs);
NOTE: An instance of an ExecutionStrategy can only be used for a single action.

Using your own IRetryDelayStrategy or IRetriableExceptionDetector

If you wish to replace the implementations of the IRetryDelayStrategy or the IReliableExceptionDetector without writing your own ExecutionStrategy then you can do so by using the ExecutionStrategy class in EF.
If you only need to execute a single action, then you can create an instance of the ExecutionStrategy class in EF and pass it the IRetryDelayStrategy and IRetriableExceptionDetector that you want to use.
If you want to register the execution strategy so that EF will use it for all actions, then you need to a create a class that implements IDependencyResolver interface. The GetService method of the resolver should return an instance of the ExecutionStrategy class with appropriate IRetryDelayStrategy and IReliableExceptionDetector implementations passed into the constructor. This class can be added to the dependency resolver in the same way that the SqlExecutionStrategyResolver is added in the example above.

Buffering

Buffering is required when using connection resiliency in order to keep the state manager consistent when there is a retry. However, there are also other benefits to buffering the main ones being:
  1. The connection is potentially open and in-use for a shorter period of time
  2. Multiple Active Result Sets (MARS) would not be needed for nested queries, such as those that come with lazy loading.
Because of this buffering is now the default. We will provide an AsStreaming method on IQueryable to allow the old behavior, similar to the AsNoTracking method for non-tracking queries.

Implementation

When in streaming mode EF uses a data reader that is wrapped in an IEnumerable that reads from the data reader as rows are required for materialization.
With the buffering enabled the process is the same, except that the underlying provider DataReader will be read into memory, and close the connection, before it begins to yield rows from in-memory collection of data.

AsStreaming

An AsStreaming extension method will be added to IQueryable that will return a query that will use the streaming behavior described above.

Viewing all articles
Browse latest Browse all 10318

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>