Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

C# - Generic Retry Mechanism

0.00/5 (No votes)
3 Apr 2017 3  
Demo for generic retry mechanism

Introduction

When you develop an application, you may have to execute a set of methods in sequential order to complete the business requirements. If you got an exception from one of the methods, the entire process will fail. The exception may occur when you connect the external services or network connection issue or other external factors. If you retry the failure process with specified interval, you may get a success result and you can execute the rest of the methods.

You can use the retry mechanism in two different situations:

  1. Getting exception when you execute a method
  2. A method may not return an expected result

Application Demo

I want to explain one demo application to describe the need of retry mechanism.

There are three methods needed to execute from the main method, if it fails, the main method will retry the failed methods.

/// <summary>
/// Send mail
/// </summary>
/// <returns>true/false</returns>
private static bool SendEmail()
{

    Console.WriteLine("Sending Mail ...");
    
    // simulate error
    Random rnd = new Random();
    var rndNumber = rnd.Next(1, 10);
    if (rndNumber != 3)
        throw new SmtpFailedRecipientException();
        
    Console.WriteLine("Mail Sent successfully");
    return true;
}

/// <summary>
/// Create database connection
/// </summary>
/// <returns>true/false</returns>
private static bool ConnectDatabase()
{
    Console.WriteLine("Trying to connect database ...");
    
    // simulate the error
    throw new Exception("Not able to connect database");
}

/// <summary>
/// Random number
/// </summary>
/// <returns>random number</returns>
private static int GetRandomNumber()
{
    Random rnd = new Random();
    // Generate the random number between 1-10
    var result = rnd.Next(1, 10);
    
    Console.WriteLine(result.ToString());
    
    return result;
}

static void Main(string[] args)
{
    // Send mail with 10 retries
    Console.WriteLine("Send mail, if it fails then try 10 times");
    
    var isSuccess = Retry.Execute(() => SendEmail(), new TimeSpan(0, 0, 1), 10, true);            
    
    if (!isSuccess)
        Console.WriteLine("Unable to send a mail");
        
    // Connect database
    var connectionStatus = Retry.Execute(() => ConnectDatabase(), new TimeSpan(0, 0, 2), 5, true);
    if (!connectionStatus)
        Console.WriteLine("Unable connect database");
        
    // Print Random number till the random number is 4
    Console.WriteLine("Print Random number till the random number is 4");
    Retry.Execute(() => GetRandomNumber(), new TimeSpan(0, 0, 1), 10, 4);
    
    Console.ReadLine();
}

Here are the ways to implement the Retry mechanism in different situations.

Output

Generic Retry Class

public class Retry
    {
        /// <summary>
        /// Generic Retry
        /// </summary>
        /// <typeparam name="TResult">return type</typeparam>
        /// <param name="action">Method needs to be executed</param>
        /// <param name="retryInterval">Retry interval</param>
        /// <param name="retryCount">Retry Count</param>
        /// <param name="expectedResult">Expected Result</param>
        /// <param name="isExpectedResultEqual">true/false to check equal 
        /// or not equal return value</param>
        /// <param name="isSuppressException">
        /// Suppress exception is true / false</param>
        /// <returns></returns>
        public static TResult Execute<TResult>(
          Func<TResult> action,
          TimeSpan retryInterval,
          int retryCount,
          TResult expectedResult,
          bool isExpectedResultEqual = true,
          bool isSuppressException = true
           )
          {
            TResult result = default(TResult);

            bool succeeded = false;
            var exceptions = new List<Exception>();

            for (int retry = 0; retry < retryCount; retry++)
            {
                try
                {
                    if (retry > 0)
                        Thread.Sleep(retryInterval);
                    // Execute method
                    result = action();

                    if (isExpectedResultEqual)
                        succeeded = result.Equals(expectedResult);
                    else
                        succeeded = !result.Equals(expectedResult);
                }
                catch (Exception ex)
                {
                    exceptions.Add(ex);
                }

                if (succeeded)
                    return result;
            }

            if (!isSuppressException)
                throw new AggregateException(exceptions);
            else
                return result;
        }
    }

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here