Skip to content

Instantly share code, notes, and snippets.

@wingrime
Created May 27, 2019 08:59
Show Gist options
  • Save wingrime/2083cfea37cb0cfee61b0565f74d2f80 to your computer and use it in GitHub Desktop.
Save wingrime/2083cfea37cb0cfee61b0565f74d2f80 to your computer and use it in GitHub Desktop.
C# exponential backoff
public static class Retry
{
public static async Task<T> DoAsync<T>(Func<Task<T>> action,
Func<T, bool> validateResult = null,
int maxRetries = 10, int maxDelayMilliseconds = 2000, int delayMilliseconds = 200)
{
var backoff = new ExponentialBackoff(delayMilliseconds, maxDelayMilliseconds);
var exceptions = new List<Exception>();
for (var retry = 0; retry < maxRetries; retry++)
{
try
{
var result = await action()
.ConfigureAwait(false);
var isValid = validateResult?.Invoke(result);
if (isValid.HasValue && isValid.Value)
return result;
}
catch (Exception ex)
{
exceptions.Add(ex);
await backoff.Delay()
.ConfigureAwait(false);
}
}
throw new AggregateException(exceptions);
}
private struct ExponentialBackoff
{
private readonly int _delayMilliseconds;
private readonly int _maxDelayMilliseconds;
private int _retries;
private int _pow;
public ExponentialBackoff(int delayMilliseconds, int maxDelayMilliseconds)
{
_delayMilliseconds = delayMilliseconds;
_maxDelayMilliseconds = maxDelayMilliseconds;
_retries = 0;
_pow = 1;
}
public Task Delay()
{
++_retries;
if (_retries < 31)
{
_pow = _pow << 1; // m_pow = Pow(2, m_retries - 1)
}
var delay = Math.Min(_delayMilliseconds * (_pow - 1) / 2, _maxDelayMilliseconds);
return Task.Delay(delay);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment