Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
using System;
using System.Configuration;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using log4net;
namespace Utils
{
public static class RetryHelper
{
//I am using log4net but swap in your favourite
private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public static async Task RetryOnExceptionAsync(
int times, TimeSpan delay, Func<Task> operation)
{
await RetryOnExceptionAsync<Exception>(times, delay, operation);
}
public static async Task RetryOnExceptionAsync<TException>(
int times, TimeSpan delay, Func<Task> operation) where TException : Exception
{
if (times <= 0)
throw new ArgumentOutOfRangeException(nameof(times));
var attempts = 0;
do
{
try
{
attempts++;
await operation();
break;
}
catch (TException ex)
{
if (attempts == times)
throw;
await CreateDelayForException(times, attempts, delay, ex);
}
} while (true);
}
private static Task CreateDelayForException(
int times, int attempts, TimeSpan delay, Exception ex)
{
var delay = IncreasingDelayInSeconds(attempts);
Log.Warn($"Exception on attempt {attempts} of {times}. " +
"Will retry after sleeping for {delay}.", ex);
return Task.Delay(delay);
}
internal static int[] DelayPerAttemptInSeconds =
{
(int) TimeSpan.FromSeconds(2).TotalSeconds,
(int) TimeSpan.FromSeconds(30).TotalSeconds,
(int) TimeSpan.FromMinutes(2).TotalSeconds,
(int) TimeSpan.FromMinutes(10).TotalSeconds,
(int) TimeSpan.FromMinutes(30).TotalSeconds
};
static int IncreasingDelayInSeconds(int failedAttempts)
{
if (failedAttempts <= 0) throw new ArgumentOutOfRangeException();
return failedAttempts > DelayPerAttemptInSeconds.Length ? DelayPerAttemptInSeconds.Last() : DelayPerAttemptInSeconds[failedAttempts];
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment