.NET 5.0 resilient HTTP client with Polly and Flurl
Applications that consume/produce any kind of data to remote servers (Apis) must have a policy to deal with transient faults. Transient faults are types of failures that are temporary and it’s likely to disappear soon, like package loss, network connectivity issues, etc.
Our application should not crash on behavior in the wrong way when some of these failures occur. We can rely on some patterns to avoid these kinds of behaviors, like Retry pattern, Circuit Break, Timeout, etc. In today’s post, we are going over how we can implement the retry pattern in C# using Polly and Flurl.
Installing the packages
In this example, we will use two packages, Polly and Flurl.
Polly is a resilience .NET library that helps developers to implement several resilient patterns such as Retry, Circuit break, and Timeout. To install it, type the command below on your Nuget Package Manager Console:
Flurl is a fluent HTTP client for .NET, which will help us dispatch requests in a simple way. With its fluent interface structure, we can build requests through chaining method calls, reducing the amount of code we need to write to make a simple HTTP request. In order to make the Furl work properly, we need to install two packages:
Creating the HTTP Client
Let’s create a class to centralize all the logic to deal with HTTP requests. This allows us to reuse this client through our codebase whenever we want to make a request. I Will call it
The first thing we are going to do in this class is to create two methods. The first method basically tells if an exception is worth retry, in other words, if the error raised is a transient error.
The second method is to build the retry policy, using the Polly library previously installed.
We are specifying in the policy creation to handle the
FlurlHttpExceptionexception since the Flurl library will be used to dispatch the request.
IsTransientError method will be used to determine if we should retry the failed request. If the status code present on the exception is equal to any status code worth retrying, a new attempt will be made by the policy.
Last but not least, the
WaitAndRetryAsync the method will be executed every time a request fails. This method receives the total number of retry to be made (three in this case), and a method that will be invoked with the current attempt and is expected to return a timestamp to be used to space the retry attempts.
The time between each retry attempt will be the current attempt number squared, in other words, the first attempt will wait one second, the second attempt 4 seconds, and the last attempt 9 seconds. This idea of using exponential backoff allows us to give more time to the remote server to recovery itself from this temporary failure.
With the policy ready, we can now begin to dispatch the HTTP requests. First of all, let’s create a method to dispatch the GET requests, without using the policy previously created.
As you can see, with Flurl, we can dispatch a request and deserialize its response with just 3 lines of code (it could be only one). The last step is to connect the call to the policy created, so the policy can listen for errors if any occur and invoke our retry strategy.
We can do that by just passing the dispatch logic to the
ExecuteAsync method exposed by the policy:
If anything goes wrong inside the
ExecuteAsync method, the policy will use the
IsTransientError to determine if it is worth retrying the executed code. If yes, a new attempt will be made, otherwise, the exception will be thrown to the client which originally invokes the
And that’s it, with approximately 50 lines of code we just created an HTTP client which will be smart enough to identify a transient error and retry at least three times before it finally fails. We can use this policy to dispatch other types of requests, such as POST, PUT, PATCH, and DELETE.
That’s all for today, folks. I hope that this article has helped you in some way.
Take care and happy coding!
The whole client code is available here.