Implementing retry logic for deadlock exceptions

c#, database-deadlocks, entity-framework, repository-pattern, try-catch

Solution

How about something like this:

public T DeadlockRetryHelper<T>(Func<T> repositoryMethod, int maxRetries)
{
  int retryCount = 0;

  while (retryCount < maxRetries)
  {
    try
    {
      return repositoryMethod();
    }
    catch (SqlException e) // This example is for SQL Server, change the exception type/logic if you're using another DBMS
    {
      if (e.Number == 1205)  // SQL Server error code for deadlock
      {
        retryCount++;
      }
      else
      {
        throw;  // Not a deadlock so throw the exception
      }
      // Add some code to do whatever you want with the exception once you've exceeded the max. retries
    }
  }
}

With the above code, your retry logic is all in this method and you can just pass your repository method in as a delegate.

Problem

I've implemented a generic repository and was wondering if there is a smart way to implement a retry logic in case of a deadlock exception? The approach should be the same for all repository methods. So is there anyway I can avoid writing 'try/catch - call method again with retry-count', in every single method? Any suggetsion are welcome. A bit of my Repository code: ``` public class GenericRepository : IRepository { private ObjectContext _context; public List<TEntity> ExecuteStoreQuery<TEntity>(string commandText, params object[] parameters) where TEntity : class { List<TEntity> myList = new List<TEntity>(); var groupData = _context.ExecuteStoreQuery<TEntity>(commandText, parameters); return myList; } public IQueryable<TEntity> GetQuery<TEntity>() where TEntity : class { var entityName = GetEntityName<TEntity>(); return _context.CreateQuery<TEntity>(entityName); } public IEnumerable<TEntity> GetAll<TEntity>() where TEntity : class { return GetQuery<TEntity>().AsEnumerable(); } ``` EDIT: 1.Solution: Modified slightly from chris.house.00's solution ``` public static T DeadlockRetryHelper<T>(Func<T> repositoryMethod, int maxRetries) { var retryCount = 0; while (retryCount < maxRetries) { try { return repositoryMethod(); } catch (System.Data.SqlClient.SqlException ex) { if (ex.Number == 1205)// Deadlock retryCount++; else throw; } } return default(T); } ``` And you call it like this: ``` public TEntity FirstOrDefault<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity : class { return RetryUtility.DeadlockRetryHelper<TEntity>( () =>p_FirstOrDefault<TEntity>(predicate), 3); } protected TEntity p_FirstOrDefault<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity : class { return GetQuery<TEntity>().FirstOrDefault<TEntity>(predicate); } ```

Original source