Using Polly v8 with HttpClientFactory

4 min readFeb 23, 2024


In approximately November of 2023 the Polly project moved from v7 to its new v8 implementation. With this new version came a completely different syntax for implementing resilience policies along with a completely changed code object model and a whole new set of types to use. New policies were made available and some were removed and the underlying engine of Polly was streamlined.

I decided to put this quick blog post together as a quick cheat sheet for folks to show how you can quickly move from old V7 to V8 of Polly with minimum friction.

Polly vs Polly.Core

So why this blog? Well the new Polly v8 library contains completely new and breaking syntax format. In order to prevent issues with existing applications the core maintainers of the library decided to split the repo into 2 separate packages:

  • Polly — continues to have the old syntax folks know, but also includes a shim wrapper to enable the new syntax. This means that you can in theory try to migrate without changing your library. It also means people who move to the new library will not cause a conflict for other packages using older versions.
  • Polly.Core — this is where Polly team want you to get to, it only supports the new v8 syntax is is optimised as such to provide many perf benefits. But it completely cuts you out of the old syntax etc.

For more detailed info please review the Polly team migration guide here

New syntax

Polly v8 completely revamps the syntax for policies, and IMO massively simplifies the implementation.

Take for example the following policy defined in the old Polly syntax:

In the new v8 syntax this simply becomes:

As you can likely see the new syntax is slightly more verbose, but it provides the following benefits:

  • There is now a much more fluent chaining of resilience policies.
  • PolicyWrap is now intrinsically provided for you under the covers of the ResiliencePipelineBuilder .
  • You no longer have to declare something using the sync or async as the new ResiliencePipelineBuilder pattern automatically provides both options to us.
  • Configuration of your pipelines is no longer convoluted by method overloads and can now be done via a simple <policy>StrategyOptions pattern where <policy> refers to the type of resilience policy being added into the pipeline.
  • The new builder pattern easily helps developers understand the explicit order in which policies will be executed rather than order of parameters passed to convoluted PolicyWrap .

Using v8 Polly with HttpClientFactory

Hopefully most of you are using resilience policies with your HttpClient via the HttpClientBuilder extensions library provided via the Microsoft.Extensions.Http.Polly nuget. I won’t go into the details of this but if you’d like to read more then please see this Microsoft learning article.

Unfortunately due to the fact that the v8 version of Polly has all new types and a new builder pattern syntax this will no longer work. So instead you should look to use the new Microsoft.Extensions.Http.Resilience nuget found here

Assuming you know Polly v8 then the migration path is quite simple. Lets assume you have the following Polly v7 resilience policy:

In the new Polly v8 world using Microsoft.Extensions.Http.Resilience this will now look something like this:

Things to note:

  • When you call AddCircuitBreaker in your pipeline you should be using the Http prefixed options objects such as HttpCircuitBreakerStrategyOptions which helps with wiring up the types of exceptions to handle nicely.
  • The new HttpCircuitBreakerStrategyOptions also nicely encapsulate all of the old HandleTransientHttpError logic for you too which will check the response message status codes.
  • If you configure a timeout on the HttpClient (as shown above) YOU MUST MANUALLY add a circuit breaker into your resilience pipeline to handle the TaskCanceledException as the Polly helper code does not see this as a “Transient issue”
  • The return type of myGetCircuitBreakerPolicy method is actually void rather than returning a policy or a builder. This is because you must now mutate the ResiliencePipelineBuilder given to you by the AddResilienceHandler extension by adding your policy definitions.
  • The AddResilienceHandler requires a string name for your policy. This may not make much sense, but it is worth noting that under the hood our policies are added to a concurrent dictionary/registry to allow the builder to quickly retrieve policies and prevent duplication.
  • There is a handy AddStandardResilienceHandler method that can be used which sets you up an opinionated default “best practice” pipeline documented on the nuget page
  • This AddStandardResilienceHandler method you will provide you with a resilience pipeline that has:
    — “total timeout” pipeline applies an overall timeout to the execution of all sub policies below, ensuring that the request including hedging attempts, does not exceed the configured limit.
    — A retry pipeline retries the request in case the dependency is slow or returns a transient error.
    — A rate limiter pipeline limits the maximum number of requests being send to the dependency.
    — A circuit breaker blocks the execution if too many direct failures or timeouts are detected.
    — A timeout pipeline which limits each request attempt duration and throws if its exceeded.

Thanks for reading, I will do a more in depth blog about the new features of Polly v8 in a future blog.




Software engineer & lover of all things code. Too much to learn and so little time. Currently working at Trainline London.