Skip to content

Instantly share code, notes, and snippets.

@costr
Last active May 30, 2019 03:44
Show Gist options
  • Save costr/3fd3b56591622a43cf6556a84c827872 to your computer and use it in GitHub Desktop.
Save costr/3fd3b56591622a43cf6556a84c827872 to your computer and use it in GitHub Desktop.
Retry Utility
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Configuration;
namespace Utiltiies
{
public class ExecutionBuilder
{
private int _numberOfRetries;
private List<TimeSpan> _intervals;
public ExecutionBuilder()
{
_numberOfRetries = GetDefaultMaxRetriesCount();
_intervals = GetDefaultTimeInterval();
}
/// <summary>
/// Allows overriding the default number of retries.
/// </summary>
/// <param name="retries"></param>
/// <returns></returns>
public ExecutionBuilder WithNumberOfRetries(int retries)
{
_numberOfRetries = retries;
return this;
}
/// <summary>
/// Allows overriding the default amount of seconds between retries.
/// </summary>
/// <param name="secondsBetweenRequests"></param>
/// <returns></returns>
public ExecutionBuilder WithInterval(int secondsBetweenRequests)
{
_intervals = new List<TimeSpan>
{
TimeSpan.FromSeconds(secondsBetweenRequests)
};
return this;
}
/// <summary>
/// Allows specifying a list of intervals to use for timeouts between retries
/// NOTE: If specifying a list of intervals you do not need to specify the retry count as it will assume
/// </summary>
/// <param name="intervals"></param>
/// <returns></returns>
public ExecutionBuilder WithIntervals(int[] intervals)
{
_intervals = intervals.Select(x => TimeSpan.FromSeconds(x)).ToList();
_numberOfRetries = _intervals.Count;
return this;
}
/// <summary>
/// The execution of a void method which needs to be retried on exception
/// </summary>
/// <param name="methodToPerform"></param>
public void RunWithRetry(Action methodToPerform)
{
RunWithRetry<object>(() =>
{
methodToPerform();
return null;
});
}
/// <summary>
/// The execution of a typed method which needs to be retried on exception
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="methodToPerform"></param>
/// <returns></returns>
public T RunWithRetry<T>(Func<T> methodToPerform)
{
var encounteredExceptions = new List<Exception>();
for (var attempted = 0; attempted <= _numberOfRetries; attempted++)
{
try
{
if (attempted < 1)
{
return methodToPerform();
}
var retryAttemptCount = attempted - 1;
var interval = _intervals.Count == 1 || attempted > _intervals.Count ?
_intervals[0] :
_intervals[retryAttemptCount];
Thread.Sleep(interval);
return methodToPerform();
}
catch (Exception ex)
{
encounteredExceptions.Add(ex);
}
}
throw new AggregateException(encounteredExceptions);
}
private List<TimeSpan> GetDefaultTimeInterval()
{
var configValue = ConfigurationManager.AppSettings["ExecutionBuilder:DefaultIntervalSeconds"];
if (string.IsNullOrWhiteSpace(configValue))
{
return new List<TimeSpan> { TimeSpan.FromSeconds(3) };
}
if (!configValue.Contains(','))
{
return new List<TimeSpan> { TimeSpan.FromSeconds(int.Parse(configValue)) };
}
var intervals = configValue
.Split(',')
.Select(x =>
TimeSpan.FromSeconds(int.Parse(x))
)
.ToList();
return intervals;
}
private int GetDefaultMaxRetriesCount()
{
var configValue = ConfigurationManager.AppSettings["ExecutionBuilder:DefaultMaxAttemptCount"];
return string.IsNullOrWhiteSpace(configValue) ?
3 :
int.Parse(configValue);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment