Returning default values from a failed web request with Polly Fallbacks

Full source code available here.

In previous posts on Polly I showed how to use a simple retry, and a retry with a delegate that is called before the request is retried.

In this post I will show how use a Polly fallback policy, this allows a “fallback” or default value to be returned when both the request and retries fail.

The retry policy is similar to ones I have used before.

_httpRetrytPolicy = Policy.HandleResult<HttpResponseMessage>(
         r => r.StatusCode == HttpStatusCode.InternalServerError)
        .WaitAndRetryAsync(2, retryAttempt => TimeSpan.FromSeconds(retryAttempt));

The fallback policy returns a HttpResponseMessage with some cached values.

_httpRequestFallbackPolicy = Policy.HandleResult<HttpResponseMessage>(
         r => r.StatusCode == HttpStatusCode.InternalServerError)
         .FallbackAsync(new HttpResponseMessage(HttpStatusCode.OK)
         {
             Content = new ObjectContent(_cachedList.GetType(), _cachedList, new JsonMediaTypeFormatter())
         });

Using the polices is almost the same as in my earlier posts, the httpClient.GetAsync is executed by the retry policy. The retry policy is executed by the fallback policy. The Polly documentation refers to this as a “‘Russian-Doll’ or ‘onion-skin-layers’ model”.

HttpResponseMessage httpResponse =  
   await _httpRequestFallbackPolicy.ExecuteAsync( () 
   =>  _httpRetrytPolicy.ExecuteAsync(()
   =>  httpClient.GetAsync(requestEndpoint)));

The above call inside a call can also be done with a Polly policy wrap, I will demonstrate that in later post.

If the request succeeds the first time, the response is assigned to httpResponse. If the request fails, the retry policy kicks in and retries up to three times. If all of those fail, the fallback policy returns a httpResponse containing the cached list.

Full source code available here.

Re-authorization and onRetry with Polly

Full source code available here.

In a previous post I showed how to use Polly to make a simple call, retrying in the event of failure. In another I showed how to let a request fail and process the response.

In this post I will show a retry where a delegate is called as part of the retry. A common use case for this is reauthorizing after an Unauthorized response.

The difference between this policy and the ones in my previous posts is very small.

public class ValuesController : ApiController
{
    readonly RetryPolicy<HttpResponseMessage> _httpRequestPolicy;
    private HttpClient _httpClient;
    public ValuesController()
    {
        _httpRequestPolicy = Policy.HandleResult<HttpResponseMessage>(
                r => r.StatusCode == HttpStatusCode.InternalServerError ||
                     r.StatusCode == HttpStatusCode.Unauthorized)
            .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(retryAttempt), onRetry: (response, timespan) =>
            {
                if (response.Result.StatusCode == HttpStatusCode.Unauthorized)
                {
                    PerformReauthorization();
                }
            });
    }

The onRetry delegate is the new part –

onRetry: (response, timespan) =>
{
	if (response.Result.StatusCode == HttpStatusCode.Unauthorized)
	{
		PerformReauthorization();
	}
}

In my PerformReauthorization I create a new HttpClient and pass it the new authorization code. For simplicity I am passing a code in the cookie of my request, you could of course use Basic Authentication or any another technique.

private void PerformReauthorization()
{
    // here you would get a new token, call some other service, etc.
    _httpClient = GetHttpClient("GoodAuthCode"); // pass in the good auth token
}

The important thing to note is that my HttpClient instance is class level, meaning it can be accessed from PerformReauthorization.

The call to the web service remains the same.

HttpResponseMessage httpResponse = await _httpRequestPolicy.ExecuteAsync(() => _httpClient.GetAsync(requestEndpoint))

I’ll post of fallbacks soon, they allow a default value to be returned in the event of repeated failures.

For completeness here is GetHttpClient.

private HttpClient GetHttpClient(string authCookieValue)
{
    var cookieContainer = new CookieContainer();
    var handler = new HttpClientHandler() {CookieContainer = cookieContainer};
    cookieContainer.Add(new Uri("http://localhost"),new Cookie("Auth", authCookieValue));
    _httpClient = new HttpClient(handler);
    _httpClient.BaseAddress = new Uri(@"http://localhost:2629/api/");

    _httpClient.DefaultRequestHeaders.Accept.Clear();
    _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    return _httpClient;
}

Full source code available here.

Letting a request fail with Polly

Polly is fantastic for transparently retrying a request but there is always a point at which you must give up. Here you have a choice, let the request fail and inform the original caller or use the Fallback feature of Polly. In this post I’m going to show how to let the request fail. I’ll post another time on the Polly Fallback feature.

With Polly, failing is done in much the same was as you would do without Polly. Make the request, examine the response, return the appropriate status to the caller.

The example code below shows this when calling a Web Api 2 endpoint. The hoped for response is Ok (200), any other is considered a failure.

HttpResponseMessage httpResponse = await _policies.RequestTimeoutPolicy.ExecuteAsync(() => httpClient.GetAsync(requestEndpoint));

if (httpResponse.IsSuccessStatusCode)
{
    int number = await httpResponse.Content.ReadAsAsync<int>();
    return Ok(number);
}

string errorMessage = await httpResponse.Content.ReadAsStringAsync();
return Content(httpResponse.StatusCode, errorMessage);

Fallback would all me to return some default number and OK even if the web request failed. Coming soon…

Reusing Polly Policies with Dependency Injection

Download full source code.

In my previous post “A simple Polly example with WebApi 2” I showed how to make a request to an unreliable endpoint protected by a Polly retry policy. For more on Polly see www.thepollyproject.org.

In that example I created the Polly policy in the constructor of the controller. That of course means it was not reusable, I would have to copy that code into all other controllers that needed the policy, and any policy changes would require me to edit all the controllers. Not a good solution.

In this post I’m going to show how to use dependency injection to share and reuse Polly policies.

Using Dependency Injection with Polly

In this example I’m working with ninject, but you you can use any DI that suits you. See here for more info on ninject – “Web API 2 and ninject, how to make them work together”.

I firstly create all my Polly policies in a simple class like so –

public class Policies
{
    public readonly RetryPolicy<HttpResponseMessage> InternalServerErrorPolicy;
    public readonly RetryPolicy<HttpResponseMessage> RequestTimeoutPolicy;
    public Policies()
    {
        InternalServerErrorPolicy = Policy.HandleResult<HttpResponseMessage>(
           r => r.StatusCode == HttpStatusCode.InternalServerError)
       .WaitAndRetryAsync(3,
           retryAttempt => TimeSpan.FromSeconds(retryAttempt));

        RequestTimeoutPolicy = Policy.HandleResult<HttpResponseMessage>(
            r => r.StatusCode == HttpStatusCode.RequestTimeout)
        .WaitAndRetryAsync(3, 
            retryAttempt => TimeSpan.FromSeconds(Math.Pow(0.2, retryAttempt)));
    }
}

Then my DI class I register the Policies.

private static void RegisterServices(IKernel kernel)
{
    kernel.Bind<Policies>().ToSelf().InSingletonScope();
}

My controllers take Policies as a constructor parameter, which ninject provides.

public class ItemsController : ApiController
{
    private readonly Policies _policies;
    public ItemsController(Policies policies)
    {
        _policies = policies;
    }
//snip...

The action methods call other controllers wrapped by one of the policies.

HttpResponseMessage httpResponse =
  await _policies.InternalServerErrorPolicy.ExecuteAsync(
     () => httpClient.GetAsync(requestEndpoint));

and

HttpResponseMessage httpResponse = 
  await _policies.RequestTimeoutPolicy.ExecuteAsync(
     () => httpClient.GetAsync(requestEndpoint));

That’s it.

Download full source code.

A simple Polly example with WebApi 2

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 of 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.