Simple Retry Helper

Hackered
Monday, August 11, 2014
by Sean McAlinden

In my work and side projects I often find I am testing against online services including a lot of cloud based REST API's.

A common problem with cloud based API's is transient network errors.

Transient network errors are caused by a multitude of different reasons which is a much larger area of discussion than this post will cover.

From a developer and tester perspective we just to be sure we gracefully handle this expected behaviour.

Lets say for example we need to create an account within a cloud service as a precondition to an acceptance test, there is nothing worse than this pre-test setup method to fail due to a transient network error, this is where having a little retry logic can be invaluable.

The following may not be the best code ever and I'm not 100% if I wrote it or scavenged it from the internet, it has however been with me a while and is a really useful little helper.

I hope you find it useful.

 

Example Usage:

The method accepts the following:

  • Action or Func: (the method to call)
  • Retry interval (how long between attempts)
  • Retry count (how many times to call the method)
RetryHelper.Do(MyVoidMethod, TimeSpan.FromMilliseconds(200), 3);
var myValue = RetryHelper.Do(MyMethodWithReturn, TimeSpan.FromMilliseconds(200), 3); 

Here is the RetryHelper class:

/// <summary>
/// Simple class for retrying an action.
/// </summary>
public static class RetryHelper
{
    /// <summary>
    /// Does the specified action.
    /// </summary>
    /// <param name="action">The action.</param>
    /// <param name="retryInterval">The retry interval.</param>
    /// <param name="retryCount">The retry count.</param>
    public static void Do(Action action, TimeSpan retryInterval, int retryCount = 3)
    {
        Do<object>(
            () =>
            {
                action();
                return null;
            },
        retryInterval,
        retryCount);
    }
 
    /// <summary>
    /// Does the specified action.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="action">The action.</param>
    /// <param name="retryInterval">The retry interval.</param>
    /// <param name="retryCount">The retry count.</param>
    /// <returns></returns>
    /// <exception cref="System.AggregateException"></exception>
    public static T Do<T>(Func<T> action, TimeSpan retryInterval, int retryCount = 3)
    {
        var exceptions = new List<Exception>();
 
        for (var retry = 0; retry < retryCount; retry++)
        {
            try
            {
                return action();
            }
            catch (Exception ex)
            {
                exceptions.Add(ex);
                Thread.Sleep(retryInterval);
            }
        }
 
        throw new AggregateException(exceptions);
    }
}