Created
May 27, 2019 08:59
-
-
Save wingrime/2083cfea37cb0cfee61b0565f74d2f80 to your computer and use it in GitHub Desktop.
C# exponential backoff
This file contains hidden or 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
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