Last active
May 30, 2019 03:44
-
-
Save costr/3fd3b56591622a43cf6556a84c827872 to your computer and use it in GitHub Desktop.
Retry Utility
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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