'Why is not working EF Core retry on failure

I've configured my db context to retry on failure this way:

optionsBuilder.UseSqlServer(connectionString, sqlServerOptionsAction: sqlOptions => {
                sqlOptions.EnableRetryOnFailure(
                maxRetryCount: 10,
                maxRetryDelay: TimeSpan.FromSeconds(30),
                errorNumbersToAdd: null);
            });

Also I have configured following interceptor:

public class DbCommandFailureInterceptor : DbCommandInterceptor
    {
        private int retryCount = 2;

        public override async Task<InterceptionResult<int>> NonQueryExecutingAsync(DbCommand command, CommandEventData eventData, InterceptionResult<int> result, CancellationToken cancellationToken = default)
        {
            Throw(command);
            return result;
        }

        public override async Task<InterceptionResult<DbDataReader>> ReaderExecutingAsync(DbCommand command, CommandEventData eventData, InterceptionResult<DbDataReader> result, CancellationToken cancellationToken = default)
        {
            Throw(command);
            return result;
        }

        private void Throw(DbCommand command)
        {
            if (!(command.CommandText.Contains("serverproperty")
        || command.CommandText.Contains("_MigrationHistory"))
        && retryCount > 0) {
                --retryCount;
                throw SqlExceptionFaker.Error10053;
            }
        }
    }

So basically I'm expecting when fetching entities from the database to hit Throw method 3 times, 2 with throwing exception and last time without throwing it. But actually there is no retry on failure and after first exception execution is getting stopped. What am I doing wrong?

I have such helper for resilient transactions:

public class ResilientTransaction
    {
        private readonly DbContext _context;
        private ResilientTransaction(DbContext context) =>
            _context = context ?? throw new ArgumentNullException(nameof(context));

        public async Task ExecuteAsync(Func<Task> action)
        {
            var strategy = _context.Database.CreateExecutionStrategy();
            await strategy.ExecuteAsync(async () => {
                using (var transaction = await _context.Database.BeginTransactionAsync()) {
                    await action();
                    await transaction.CommitAsync();
                }
            });
        }

        public static ResilientTransaction New(DbContext context) =>
            new ResilientTransaction(context);
    }

And here is the way I am executing it:

await ResilientTransaction.New(_dbContext).ExecuteAsync(async () => {
                    _dbContext.Tenants.Add(new Tenant());
                    await _dbContext.SaveChangesAsync();
                });


Solution 1:[1]

Short answer: this is because this particular implementation of retry strategy retries only for specific exceptions (like timeout for sql) .

If you want retries work for your test you need to throw these specific exceptions (which could be not an easy task with some hacks) or better write your own custom retry strategy and use it in db context, but for testing only!

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Maks