In today’s software development world, almost all applications are connected. In some or many ways they’re connected to network-based services. The Internet is one such network, which sometimes is not reliable due to slow connections, timeouts, and other connection un-availability issues. It is most important for any application to handle such situations in a graceful manner. That means, these things happen and are meant to happen, so how should an application respond to these scenarios without reducing the “Reliability” factor?
An example scenario
Let’s take an example of an application that displays some information from an RSS/Atom feed. Now once in a while, the RSS/Atom host server becomes unreachable for a short span of time (say 10-20 sec.) due to the above-mentioned reasons. We have a couple of options to deal with such situations. Try reading from the feed, and when there’s an error, show the user that the feed is not available and try again. The user tries again and the application successfully reads the feed and displays the information to the user. Or the application can retry the fetch operation a couple of times, and when it’s available display the information to the user without any user interaction. This depends on the business scenario but it increases Reliability.
A high-level view of the Retry mechanism
When to apply the Retry mechanism
In most scenarios at least, important read operations can be marked to engage the server with Retry operation for specific errors like network timeout, connection unreachable, etc. Another example that I assume everybody has seen while downloading something from the Internet and the connection goes down, is the browser waits and retries for some time before actually aborting the download.
Implementation
To introduce this behavior I prefer
TrasientFaultHandling from Microsoft Practice Enterprise library. It’s
available as an individual NuGet package so you won’t need to install the whole Enterprise Library monster project. Although you can use any other utility which provides a Retry mechanism or implement your own, IMO if something is already there, well-tested, and optimized then why wasting time re-inventing the wheel.
Installing Nuget package
Add the NuGet package
TransientFaultHandling.Core in your project to have the required library classes and methods available for usage.
Implementing Transient Fault detection policy/strategy
Transient fault/exceptions are identified as temporary errors and probably can be fixed by retrying the operation. To introduce such types of fault/exceptions we need to implement the policy/strategy by implementing the interface
ITransientErrorDetectionStrategy.
-
-
-
- internal class DownloadFeedTrasientErrorDetectionStrategy: ITransientErrorDetectionStrategy
- {
-
-
-
-
-
- public bool IsTransient(Exception ex)
- {
- return CheckIsTransientInternal(ex);
- }
-
-
-
-
-
-
- protected virtual bool CheckIsTransientInternal(Exception ex)
- {
- return CheckIsTransient(ex);
- }
-
- private static bool CheckIsTransient(Exception ex)
- {
- if (ex is TimeoutException)
- {
- return true;
- } else if (ex is WebException)
- {
- return true;
- } else if (ex is UnauthorizedAccessException)
- {
- return false;
- }
-
- return false;
- }
- }
view rawDownloadFeedTrasientErrorDetectionStrategy.cs hosted with ❤ by
GitHub
A straight forward usage of Retry utility:
- public class FeedDao {
- private readonly RetryPolicy retryPolicy;
-
- public FeedDao()
- {
-
-
- this.retryPolicy =
- new RetryPolicy < DownloadFeedTrasientErrorDetectionStrategy >
- (
- new Incremental(3, TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(1.5))
- {
- FastFirstRetry = true
- });
-
-
- this.retryPolicy.Retrying += (s, e) =>
- Trace.TraceWarning("An error occurred in attempt number {1} to download feed: {0}", e.LastException.Message, e.CurrentRetryCount);
- }
-
- public void GetFeed()
- {
- this.retryPolicy.ExecuteAction(() => this.DownloadFeed(feed_source));
- }
-
- private string DownloadFeed(string source)
- {
-
- return result;
- }
- }
view rawFeedDao.cs hosted ❤ by
GitHub.
Code Explanation:
The
RetryPolicy is a class from
the TransientFaultHandling namespace.
- this.retryPolicy = new RetryPolicy < DownloadFeedTrasientErrorDetectionStrategy > (new Incremental(3, TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(1.5))
- {
- FastFirstRetry = true
- });
The above snippet is an interesting one. Here we’ve used the Generic constructor of RetryPolicy. The class Incremental is
RetryStrategy which takes similar arguments as defined in the RetryPolicy class constructor.
- this.retryPolicy.ExecuteAction(() => this.DownloadFeed(feed_source));
The above line shows how the actual network-based method call is wrapped with Retry logic. It takes a simple void
Action delegate which is represented as
LambdaExpression.
This is the simplest usage of RetryPolicy. Really easy, isn’t it? But this is all you need to do to introduce Retry stuff in your application. Who else is using –
Entity Framework, Windows Azure service, and many other important products are using this library.