Polly Transient Fault handling UPDATE

I am now using Polly in production and it works awesomely. I followed the same fault handling policy noted on Hanselman’s blog about Polly.

var policy = Policy
.Handle<SqlException>()
.WaitAndRetry(5, retryAttempt => 
  TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), 
  (exception, span) =>
{
// Log transient error
} );

This is a decidedly easy way to implement an exponential back-off retry policy. On the first retry it waits 2 seconds, by the 5th and final retry it will wait 32 seconds. This means this sql call will wait up to 1 minute for attempting to complete the sql call (ignoring any time spent executing the sql call prior to a sql exception being raised)

Working with HttpClient is absurd

Using Microsoft.AspNet.WebApi.Client (HttpClient) safely to handle both http errors and timeouts is flatly absurd. Look at the follow giant block of code it requires to merely request a URL and record the result or failure reason.

var apiResult = new MyApiResult();

var cts = new CancellationTokenSource();
cts.CancelAfter(timeout);

using (var client = new HttpClient { BaseAddress = host }) {
try {

var response = await client.GetAsync("api", cts.Token);

apiResult.IsHostReachable = true;

if (response.IsSuccessStatusCode) {
    apiResult.Status =
        await response.Content.ReadAsAsync<MyApiStatus>();
}
else {
    string content = null;
    string reasonPhrase = null;

    try { content = await response.Content.ReadAsStringAsync(); }
    catch (Exception) { /*ignored*/ }

    try { reasonPhrase = response.ReasonPhrase; }
    catch (Exception) { /*ignored*/ }

    apiResult.FaultDescription =  string.Format("{0}-{1} {2}",
        response.StatusCode, reasonPhrase, content);
}
}
catch (Exception e) {
var canceled = e as TaskCanceledException;

if (canceled != null && cts.Token.IsCancellationRequested) {
    apiResult.FaultDescription =  host + " timed out";
}
else {
    apiResult.FaultDescription = e.Message;

    if (e.InnerException != null)
    {
        apiResult.FaultDescription +=  e.InnerException.Message;
    }
}
}
}

I apologize for the awkward placement of braces however between the length and depth of nesting involved it was very difficult to format to even display at all here.

HttpClient was created to replace how poor it was working with the WebRequest class that was from the webforms era long before RESTFUL services existed. It was supposed to eliminate the pain and make things easy to work with modern HTTP APIs. Instead it is arguably even more cumbersome to use. There isn’t even a way to handle timeouts without resorting to exception catching and Liskov Substitution violating direct casts of a base type to a more specific type.

But it supports async/await… that’s something right? right?