Search code examples
c#dotnet-httpclientpollyretry-logicpolicywrap

C# Polly combining http error handler, retry, bulkhead and timeout to be used inside HttpClient


I am trying to make some HTTP calls and I want to have retry, timeout, and bulkhead for maximum concurrent connections. This is my attempt. I don't know if the order of the WrapAsync function calls is correct. More specifically,

  • I may sometimes get 4xx or 5xx response from the server and I want Polly to handle those
  • I don't want a HttpClient to make more than 3 concurrent HTTP calls and I set the queue size to "infinite"
  • If the server did not respond in 20 seconds then timeout that attempt
  • For retries use an exponential timeout policy by exponentially increasing the timeout

My question is does this code do what I think it will do?

var betterPolicy = HttpPolicyExtensions.HandleTransientHttpError().OrTransientHttpStatusCode()
    .WaitAndRetryAsync(5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)))
    .WrapAsync(Policy.BulkheadAsync(3, int.MaxValue /* queue size */))
    .WrapAsync(Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(20)));

var httpClient = new HttpClient(new PolicyHttpMessageHandler(betterPolicy));

Solution

  • In case of Polly there are many ways to combine/chain policies. Here I have demonstrated the most common ones. I would highly encourage you to use Policy.WrapAsync static method because:

    • It is easier to interpret the escalation chain:
      • the leftmost parameter is the most outer policy
      • the rightmost parameter is the most inner policy
    • It enforces compile-time policy compatibility checks
    var resilienceStrategy = Policy.WrapAsync(sharedBulkhead, localRetry, localTimeout); 
    

    I've used the prefix shared in case of Bulkhead policy because it needs to be shared between HttpClient calls otherwise it is useless. In case of Polly most of the policies are stateless but there are a few stateful (like Circuit Breaker or Bulkhead).

    I would also suggest to read this other post of mine which details how to enforce throttling in case of HttpClient. Long story short: Bulkhead is mainly designed for CPU based computations, not for I/O bound operations. RateLimit policy might be a better fit for this.