Polly allows http retries with exponential backoff so if the resource you are trying to reach throws a transient error (an error that should resolve itself) like 500 (Server Error) or 408 (Request Timeout) then the request will auto-magically be re-tried x times with an increased back-off (the period between re-tries) before giving up.
We can include 404 (Not Found) but that depends on the use case, in some API’s 404 means the data you were looking for is not avalible. Example if GET /person/1
responded in 404 it COULD mean 1 doesnt exist but the resource is still there.
Polly can also do other cool things listed below but I’ll focus on simple retry.
- Circuit Breaker
- Fallback
- Timeout
- Bulkhead Isolation
Create the retry policy
Install nuget
Microsoft.Extensions.Http.Polly
In the DI container set the handler to be applied to the injected http client, this will be avalible to the constructor of
FooService
. The microsoft example also sets.SetHandlerLifetime(TimeSpan.FromMinutes(5))
.
1 | //ConfigureServices() - Startup.cs |
- Define the handler which will cater for
- Retry policy for 5xx, 408 and 404.
- Retry based on
RetryCount
and exponentially back-off by retryAttempt starting atRetrySleepDuration
.
Here onRetryAsync
is passed a deligate inline method that just writes out a message. This was helpful when manually testing my worker as its a console application.
1 | public static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy() |
Building on WaitAndRetryAsync => onRetry/onRetryAsync
The 3rd parameter of onRetry
is an int which represents retryAttempt
, this can be added to logs.
I also wasnt sure on the value of using async when its just a log, so I switched it out.
1 | .WaitAndRetryAsync( |
- https://www.stevejgordon.co.uk/polly-using-context-to-obtain-retry-count-diagnostics
- https://github.com/App-vNext/Polly/issues/505
- https://github.com/App-vNext/Polly/wiki/Polly-and-HttpClientFactory#use-case-exchanging-information-between-policy-execution-and-calling-code
Unit tests
You may be tempted to create additional infastructure and unit test an injected HttpClient with mocked out http responses but its simpler to just unit test the extension method. This can be done with a simple DummyMethod
that keeps track of its invocations and has a sorted and predefined collection of response http status codes.
For this test the following should be true per invocation
- 4th => HttpStatusCode.OK (200)
- 3rd => HttpStatusCode.NotFound (404)
- 2nd => HttpStatusCode.RequestTimeout (408)
- 1st => HttpStatusCode.InternalServerError (500)
1 | public class PollyExtensionTests |
References
- Implement HTTP call retries with exponential backoff with IHttpClientFactory and Polly policies
- https://www.thecodebuzz.com/httpclient-resiliency-http-polly-csharp-netcore/
- https://josephwoodward.co.uk/2020/07/integration-testing-polly-policies-httpclient-interception
- https://anthonygiretti.com/2019/03/26/best-practices-with-httpclient-and-retry-policies-with-polly-in-net-core-2-part-2/
- https://nodogmablog.bryanhogan.net/2019/03/testing-your-code-when-using-polly/