.NET › Background Services

How do you implement retry logic with exponential backoff for a background service processing potentially-failing external calls?

Advanced

Answer

Combine a retry policy (either hand-rolled or via a library like Polly) wrapping each unit of work with exponentially increasing delays between attempts (e.g., 1s, 2s, 4s, 8s) up to a maximum retry count, distinguishing between transient failures (worth retrying) and permanent failures (should be logged and skipped/dead-lettered) to avoid infinite retry loops on unrecoverable errors.
var retryPolicy = Policy
    .Handle<HttpRequestException>()
    .WaitAndRetryAsync(3, attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt)));

protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
    while (!stoppingToken.IsCancellationRequested) {
        await retryPolicy.ExecuteAsync(() => CallExternalApiAsync());
        await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
    }
}
Real-world example A background service integrating with a flaky third-party payment provider uses Polly's exponential backoff to gracefully absorb transient network blips, only escalating to an alert after three consecutive failed attempts.

Common follow-ups: How do you distinguish transient from permanent failures programmatically?;What's a dead-letter queue and how does it complement retry logic?