Retry handling
Transient HTTP failures - timeouts, server errors, rate limiting - are inevitable in distributed systems. Rather than wrapping every HTTP call in retry logic, the RetryDelegatingHandler adds automatic retry with exponential backoff at the HttpClient level.
Setting up retry handling
Register the handler with IHttpClientFactory:
services.AddHttpClient("ResilientApi")
.AddHttpMessageHandler(() => new RetryDelegatingHandler(
maxRetries: 3,
initialDelay: TimeSpan.FromSeconds(1)));
Or use it directly when constructing an HttpClient:
var handler = new RetryDelegatingHandler(
maxRetries: 3,
initialDelay: TimeSpan.FromSeconds(1));
var client = new HttpClient(handler);
How it works
The handler retries on the following conditions:
- HTTP 500 (Internal Server Error)
- HTTP 502 (Bad Gateway)
- HTTP 503 (Service Unavailable)
- HTTP 504 (Gateway Timeout)
- HTTP 429 (Too Many Requests)
- Request timeout exceptions
Each retry doubles the delay (exponential backoff):
- Retry 1: 1 second
- Retry 2: 2 seconds
- Retry 3: 4 seconds
If all retries are exhausted, the last response or exception is returned to the caller.
Using with INetworkRequestFactory
Combine the retry handler with a named client for the factory:
services.AddHttpClient("MyApi", client =>
{
client.BaseAddress = new Uri("https://api.example.com/");
})
.AddHttpMessageHandler(() => new RetryDelegatingHandler(maxRetries: 3));
services.AddNetworkRequestFactory();
// In your service
var request = requestFactory.WithClient("MyApi").Get("/data");
var result = await request.ExecuteAsync<MyData>();
// Retries automatically on transient failures
Best practices
- Set reasonable retry limits. Three retries is a good default. More than five retries usually indicates a deeper issue.
- Use exponential backoff (which is the default) to avoid overwhelming a recovering service.
- Only retry idempotent operations. GET, PUT, and DELETE are generally safe to retry. Be cautious with POST requests that create resources, as retries could create duplicates if the server processed the request but the response was lost.
- Consider using Polly for more advanced resilience patterns (circuit breakers, bulkhead isolation, hedging).
RetryDelegatingHandleris intentionally simple for straightforward retry scenarios.