TimBunting
TimBunting

Reputation: 542

SQLAzureExecutionStrategy ShouldRetryOn not being called on EF Exception

I'm trying to incorporate the SQLAzureConnectionStrategy because I have an Azure Web App that in some cases calls an On-Premises SQL Database via a Hybrid Connection. The Connection is a bit flaky and sometimes an exception occurs when reading data, but retrying immediately after is just fine.

I thought this was a good case for SQLAzureConnectionStrategy because you can configure it to do Retries.

I've set up my DbConfiguration Class:

  public class dbUnitsConfiguration : DbConfiguration
{
    public dbUnitsConfiguration()
    {
        SetExecutionStrategy("System.Data.SqlClient", () => SuspendExecutionStrategy
  ? (IDbExecutionStrategy)new DefaultExecutionStrategy()
  : new CustomExecutionStrategy(6, new TimeSpan(0, 0, 4))); 

        AddInterceptor(new dbUnitsInterceptor());
    }

    public static bool SuspendExecutionStrategy
    {
        get { return (bool?)CallContext.LogicalGetData("SuspendExecutionStrategy") ?? false; }
        set { CallContext.LogicalSetData("SuspendExecutionStrategy", value); }
    }

}

The SuspendExcutionStrategy bit is probably not necessary but I was getting desparate and trying different things I'd seen.

Here is the class I derived from SQLAzureExecutionStrategy so I could override ShouldRetryOn

  public class CustomExecutionStrategy : SqlAzureExecutionStrategy
{
    public CustomExecutionStrategy(int maxRetryCount, TimeSpan maxDelay)
        : base(maxRetryCount, maxDelay)
    {
    }


    protected override bool ShouldRetryOn(Exception exception)
    {
        Log.LogInformation("Retrying on " + exception.Message);
        return true;
    }


}

I followed the example in the article http://thedatafarm.com/data-access/testing-out-the-connection-resiliency-feature-into-ef6/ to test I had implemented it correctly by simulating an exception in the Interceptor class and this all worked fine. I can even trap it in debug and see the ShouldRetryOn being called.

However if I get an exception in the actual Entity Framework call, it is just returned as an exception and ShouldRetryOn is bypassed.

I even put in the simulated exception directly into the Entity Framework call as follows:

   public IEnumerable<Shared.Models.Client> GetAll()
    {
        // throw SqlExceptionFaker.Error10053;
        return Mapper.Map<List<Entities.GetClients_Result>, 
            List<Shared.Models.Client>>(dbContext.GetClients(null).ToList());
    }

and the exception is just returned to the calling method. SQLAzureConnectionStrategy does nothing, no retries or anything.

Any advice please, I can't see what SQLAzureConnectionStrategy does if it can't capture the exception returned by the EF call.

Thanks.

Upvotes: 4

Views: 2622

Answers (2)

Rob Sedgwick
Rob Sedgwick

Reputation: 4514

This is the way I have done it. I decorate the entity class with my DbConfigurationType class using the DbConfigurationType attribute.

[DbConfigurationType(typeof(DataContextConfiguration))]
    public partial class MyEntity : DbContext
    {
        public static MyEntity CreateContext()
        {
            var context = new MyEntity();
            ((IObjectContextAdapter)context).ObjectContext.CommandTimeout = 180;

            return context;
        }
     }


public class DataContextConfiguration : DbConfiguration
{
    public DataContextConfiguration()
    {
    SetExecutionStrategy("System.Data.SqlClient", () => new SqlAzureExecutionStrategy(5, new TimeSpan(0, 0, 10)));
    }
} 

Upvotes: 3

Rowan Miller
Rowan Miller

Reputation: 2090

However if I get an exception in the actual Entity Framework call, it is just returned as an exception and ShouldRetryOn is bypassed.

The execution strategy is only used for the database operation. So if you are saying that ShouldRetryOn is not called for an EF exception (not related to the I/O operation with the database) then that is the expected behavior.

Here is the code for SqlAzureExecutionStrategy if you want to see what it does https://entityframework.codeplex.com/SourceControl/latest#src/EntityFramework.SqlServer/SqlAzureExecutionStrategy.cs

Most of the logic is in the DbExecutionStrategy base class https://entityframework.codeplex.com/SourceControl/latest#src/EntityFramework/Infrastructure/DbExecutionStrategy.cs

Upvotes: 0

Related Questions