Retry with Exponential Backoff
csharpC# and .NETintermediatebest-practices
Retry a flaky async operation, doubling the wait between attempts.
// Demo: the operation fails twice, then succeeds, so RetryAsync makes three calls.
int calls = 0;
string result = await RetryHelper.RetryAsync(async () =>
{
calls++;
await Task.Delay(10);
if (calls < 3) throw new HttpRequestException("temporary failure");
return "ok";
}, maxAttempts: 4, initialDelay: TimeSpan.FromMilliseconds(10));
Console.WriteLine($"{result} after {calls} calls"); // ok after 3 calls
// Real use: await RetryHelper.RetryAsync(() => http.GetStringAsync(url), maxAttempts: 4);
public static class RetryHelper
{
// Waits initialDelay, then twice as long after each failure. The last failure is rethrown.
public static async Task<T> RetryAsync<T>(
Func<Task<T>> action,
int maxAttempts = 3,
TimeSpan? initialDelay = null,
CancellationToken ct = default)
{
var delay = initialDelay ?? TimeSpan.FromMilliseconds(200);
for (var attempt = 1; ; attempt++)
{
try
{
return await action();
}
catch (Exception) when (attempt < maxAttempts && !ct.IsCancellationRequested)
{
await Task.Delay(delay, ct);
delay *= 2;
}
}
}
}