Defining an HTTP Transient Error Detection Strategy For REST Calls

February 21, 2013 — 5 Comments

public class HttpTransientErrorDetectionStrategy
    : ITransientErrorDetectionStrategy
{
    private readonly List<HttpStatusCode> statusCodes = 
        new List<HttpStatusCode>
        {
            HttpStatusCode.GatewayTimeout,
            HttpStatusCode.RequestTimeout,
            HttpStatusCode.ServiceUnavailable,
        };

    public HttpTransientErrorDetectionStrategy(bool isNotFoundAsTransient = false)
    {
        if (isNotFoundAsTransient)
            statusCodes.Add(HttpStatusCode.NotFound);
    }

    public bool IsTransient(Exception ex)
    {
        var we = ex as WebException;
        if (we == null)
            return false;

        var response = we.Response as HttpWebResponse;

        var isTransient = response != null 
                                   && statusCodes.Contains(response.StatusCode);
        return isTransient;
    }
}

Microsoft released The Transient Fault Handling Application Block as part of the Microsoft Enterprise Library, which targets various Windows Azure services. An interesting aspect of this block is that its easy to extend and use.

The Transient Fault Handling Application Block is a product of the collaboration between the Microsoft patterns & practices team and the Windows Azure Customer Advisory Team. It is based on the initial detection and retry strategies, and the data access support from the Transient Fault Handling Application Framework. The new block now includes enhanced configuration support, enhanced support for wrapping asynchronous calls, provides integration of the block’s retry strategies with the Windows Azure Storage retry mechanism, and works with the Enterprise Library dependency injection container. The new Transient Fault Handling Application Block supersedes the Transient Fault Handling Framework and is now a recommended approach to handling transient faults in the cloud.

Targeted services include Windows Azure SQL Database, Windows Azure Service Bus, Windows Azure Storage, and Windows Azure Caching Service. Although These are all Cloud services, it is easy to define your own detection strategies to identify known transient error conditions.

This is exactly that I did here. I implemented the ITransientErrorDetectionStrategy interface and added logic to decide weather the exception raised by the code executed within a RetryPolicy is a transient HTTP error. I chose to flag the following HttpStatusCodes as transient:

  • HttpStatusCode.GatewayTimeout
  • HttpStatusCode.RequestTimeout
  • HttpStatusCode.ServiceUnavailable

Retry Policies are important because they solidify your code against transient faults. Transient faults are temporary and usually go away rapidly. This is why using a Retry Policy to encapsulate code is interesting. Applications that lag and continue to work are always more appreciated than applications that show popups to warn the user that an error has occurred.

The code from this Post is part of the Brisebois.WindowsAzure NuGet Package

To install Brisebois.WindowsAzure, run the following command in the Package Manager Console

PM> Install-Package Brisebois.WindowsAzure

Get more details about the Nuget Package.

 

Using the newly created HttpTransientErrorDetectionStrategy

public class MakeARestCallTest
{
    public void Execute()
    {
        var r = RetryPolicyFactory.MakeHttpTransientErrorDetectionStrategy();

        r.ExecuteAction(() =>
            {
                var wc = new WebClient();
                string uri = "http://brisebois.com/api/list";
                return wc.DownloadString(uri);
            });
    }
}

RetryPolicyFactory

public static class RetryPolicyFactory
{
    public static RetryPolicy MakeHttpRetryPolicy(int count = 10, 
                                                  bool notFoundIsTransient= false)
    {
        var strategy = new HttpTransientErrorDetectionStrategy(notFoundIsTransient);
        return Exponential(strategy,count);
    }

    private static RetryPolicy Exponential(ITransientErrorDetectionStrategy stgy,
                                            int retryCount = 10,
                                            double maxBackoffDelayInSeconds = 1024,
                                            double delta = 2)
    {
        var maxBackoff = TimeSpan.FromSeconds(maxBackoffDelayInSeconds);
        var deltaBackoff = TimeSpan.FromSeconds(delta);
        var minBackoff = TimeSpan.FromSeconds(0);

        var exponentialBackoff = new ExponentialBackoff(retryCount,
                                                        minBackoff,
                                                        maxBackoff,
                                                        deltaBackoff);
        return new RetryPolicy(stgy, exponentialBackoff);
    }
}

5 responses to Defining an HTTP Transient Error Detection Strategy For REST Calls

  1. 

    But what about fine grained control over http timeout?

    Like

    • 

      Can you provide an example of the fine grained control you would like to have?

      Like

      • 

        What about situations where someone would want to retry certain exceptions with one RetryPolicy (GateWayTimeout) with ExponentialBackoff and another (ServiceUnavailable) with Incremental?

        Detecting if a retry has occurred with the RetryPolicy.OnRetrying event and a maybe a re-initialization of the RetryPolicy instance probably won’t work. Doesn’t look like the RetryPolicy constructor support any collections.

        Like

  2. 

    I supposed it would have to be back to try/catch and handle with a different TransientErrorDetectionStrategy and RetryPolicy.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s