An example scenario
Let’s take an example of an application which displays some information from an RSS/Atom feed. Now once in a while, the RSS/Atom host server become 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 feed is not available and try again. The user tries again and the application successfully reads the feed and displays the information to 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 the Reliability.
A high level view of 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 Internet andthe 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 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 method 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 with ❤ by
GitHub.
Code Explanation:
The
RetryPolicy is a class from
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 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 simple void Action delegate which is represented as LambdaExpression.
This is a 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.