Implementing HTTP Timeout Retries with Polly and IHttpClientBuilder
By FoxLearn 1/9/2025 3:10:38 AM 72
By defining the retry behavior in one central location, you ensure that no retry-related code is mixed into the actual HttpClient
calls.
The retry mechanism in Polly is implemented using policies, which determine when and how retries are attempted. While retrying on HTTP errors such as 404 Not Found
or 500 Internal Server Error
is straightforward, dealing with HTTP timeouts is a little different. In this case, HttpClient
does not receive a response code, but rather throws a TimeoutRejectedException
when the request exceeds the time limit.
To configure retry logic for timeouts, we need to define a retry policy and wrap it with a timeout policy.
Install Required NuGet Packages
Make sure you have the following NuGet packages in your project:
- Polly
- Microsoft.Extensions.Http.Polly
Configure IHttpClientBuilder and Polly Policies in Startup
In your Startup.cs
, add an HttpClient
configuration with the retry and timeout policies.
public static IHostBuilder CreateHostBuilder(string[] args) { var host = Host.CreateDefaultBuilder(args); host.ConfigureServices((hostContext, services) => { // Register HttpClient with Polly retry and timeout policies services.AddHttpClient("HttpClient") .AddPolicyHandler(GetRetryPolicy()) .AddPolicyHandler(Policy.TimeoutAsync<HttpResponseMessage>(5)); // Timeout after 5 seconds }); return host; } private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy() { return HttpPolicyExtensions .HandleTransientHttpError() // Handles transient HTTP errors like 500 or 502 .Or<TimeoutRejectedException>() // Also handle timeouts .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(30)); // Retry 3 times with a 30s delay }
In this example:
services.AddHttpClient("HttpClient")
: Registers a namedHttpClient
instance with the retry and timeout policies.- Retry Policy: Uses
HttpPolicyExtensions.HandleTransientHttpError()
to handle common transient HTTP errors (e.g., 500, 502) and adds handling forTimeoutRejectedException
to retry on timeouts. The retry happens up to 3 times with a delay of 30 seconds. - Timeout Policy: Configures a timeout policy using
Policy.TimeoutAsync<HttpResponseMessage>(5)
, which throws aTimeoutRejectedException
if the request takes longer than 5 seconds.
Using IHttpClientFactory
Now, the class making the HTTP requests doesn't need to be aware of the retry logic or timeout settings. The retry and timeout policies are automatically applied by HttpClientFactory
.
namespace Demo { public class ExampleHttpClientFactory { private readonly IHttpClientFactory _clientFactory; public ExampleHttpClientFactory(IHttpClientFactory clientFactory) { _clientFactory = clientFactory; } public async Task<string> GetAsync(string url) { var httpClient = _clientFactory.CreateClient("HttpClient"); // Set Basic Authentication header if required SetBasicAuthHeader(httpClient, "user", "password"); // Execute GET request using var response = await httpClient.GetAsync(url); // Ensure successful response (throws exception on failure) response.EnsureSuccessStatusCode(); // Return response content as string return await response.Content.ReadAsStringAsync(); } private void SetBasicAuthHeader(HttpClient httpClient, string username, string password) { var authToken = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{username}:{password}")); httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", authToken); } } }
In this example, httpClient.GetAsync()
will automatically retry the request based on the retry policy you defined earlier. The retry will happen if the conditions in the GetRetryPolicy()
occur, and it will stop after a successful response or after exhausting the retry attempts.
Avoid Setting HttpClient.Timeout
Be cautious not to set a global HttpClient.Timeout
when using Polly’s timeout policy. Setting a timeout will override Polly’s retry logic, and you might get a TaskCanceledException
or OperationCanceledException
instead of a TimeoutRejectedException
, which won't be handled by your timeout policy.
By configuring the retry and timeout policies in IHttpClientBuilder
, you keep your HTTP client calls clean and maintainable, allowing retry logic to be applied seamlessly at the service level.
- How to fix 'Failure sending mail' in C#
- How to Parse a Comma-Separated String from App.config in C#
- How to convert a dictionary to a list in C#
- How to retrieve the Executable Path in C#
- How to validate an IP address in C#
- How to retrieve the Downloads Directory Path in C#
- C# Tutorial
- Dictionary with multiple values per key in C#