Download full source code.
If you are calling APIs and you haven’t heard about The Polly Project, you should check it out. It helps take care of many common problems like unreliable connections, retries and circuit breaking. It can also be used to wrap code where other forms of transient exception may occur.
In this blog post I’m going to show the wait and retry policy when calling an unreliable Web Api endpoint.
When using Polly there are two pieces that need you need to code – the policy and the execution of code wrapped by the policy.
In this example the policy is created in the constructor of the controller, this is NOT what you should do in a real application. For an example using DI to share policies see “Reusing Polly Policies with Dependency Injection”.
readonly RetryPolicy<HttpResponseMessage> _httpRequestPolicy; public ValuesController() { _httpRequestPolicy = Policy.HandleResult<HttpResponseMessage>( r => r.StatusCode == HttpStatusCode.InternalServerError) .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(retryAttempt)); }
This policy states that in the event that a HttpResponseMessage
has a InternalServerError
, the request should be tried up to three times with a back off increasing by one second each time.
That’s the policy in place, now we need to call the web service endpoint.
public async Task<IHttpActionResult> Get() { var httpClient = GetHttpClient(); string requestEndpoint = "numbers/"; // numbers is the name of the controller being called HttpResponseMessage httpResponse = await _httpRequestPolicy.ExecuteAsync(() => httpClient.GetAsync(requestEndpoint)); IEnumerable<int> numbers = await httpResponse.Content.ReadAsAsync<IEnumerable<int>>(); return Ok(numbers); }
If you execute the code it makes a GET
request to http://localhost:2351/api/values
, despite two failures when calling the NumbersController
you will get a 200
response and a list of numbers.
If you want to verify this, step through the provided solution with the debugger. You’ll see that the first two requests to the NumbersContoller
return 500
errors and that the third succeeds and returns an array of ints.
With just a few lines of code Polly provided us with a robust wait and retry mechanism for web requests.
In another blog I’ll show a better way of defining policies so they can be used in any controller.
Download full source code.
Pingback: Reusing Polly Policies with Dependency Injection | no dogma blog
Pingback: Re-authorization and onRetry with Polly | no dogma blog
This is the first example of Polly that I’ve seen where a policy is defined not on an exception but rather on some other condition, in this case the http status code. Am I reading this correctly? I hope so because ideally I’d like to use Polly policies on application-specific conditions that constitute “failure”.
Hey Howard. Yes, you’re reading right: this was added to Polly at v5.0, in the fall of 2016. See https://github.com/App-vNext/Polly/#step-1b-optionally-specify-return-results-you-want-to-handle and https://github.com/App-vNext/Polly/#handing-return-values-and-policytresult for more details! You can also mix handling exceptions and properties of the return-result in the same policy – useful sometimes in the Http call scenario.
That’s great. I’m glad this is the case! Thanks for responding so quickly.
How we can log the number of re-try and implement circuit breaker?
You can add an
OnRetry
delegate and execute your logging code there.Check my Pluralsight course to see how to work with the circuit breaker – https://app.pluralsight.com/library/courses/polly-fault-tolerant-web-service-requests/table-of-contents
Dylan – How would you handle and retry on conditions that have nothing to do with the http request itself. Let’s say I want to execute a policy on the body of the response; perhaps it contains some text string.
I’d suggest putting your http request into its own method and return the string from that method.
Now, use Polly to call that method checking the value of the returned string.
Something like –
_stringRetryPolicy = Policy.HandleResult (s => s != "hello world").Retry(3);
RetryPolicy
string value = _stringRetryPolicy.Execute(GetData);
private string GetData()
{
//return value from http request;
}