Jonathan George's Blog

Add Timeouts to your methods with PostSharp

Posted in Technical Stuff by Jonathan on September 15, 2009

Note: This was originally posted on my old blog at the EMC Consulting Blogs site.

In my previous post, “Make methods fire and forget with PostSharp”, I showed how a PostSharp aspect could be used to stop non-critical methods from blocking execution. Staying on a similar theme, in this post I will show how you can use the AOP framework to add timeouts to methods.

In one of my current projects, we’re using Microsoft Velocity CTP3. Whilst this is proving to be pretty good, it has an annoying tendancy to take the entire site down with it if it blows up. We therefore added some code to allow the site to keep running if the cache stops working so that the problem could be rectified without causing more than a slowdown. This code worked perfectly, but I hit the minor snag that Velocity operations like DataCacheFactory.GetCache appear to have something like a 10 second timeout. Our app will typically make tens of calls to the cache to generate a single page so whilst I stopped the site crashing, it was still unusable.

I couldn’t find a way to lower the timeout in Velocity, so I had to implement it in my own methods. The standard code for adding a 1 second timeout in a method would look something like this:

  1. public class TimeoutWithoutPostsharp
  2. {
  3.     public object MyMethod(object param)
  4.     {
  5.         var methodDelegate = new Func<object, object>(this.MyMethodInner);
  6.         var result = methodDelegate.BeginInvoke(
  7.             param,
  8.             null,
  9.             null);
  10.         if (!result.AsyncWaitHandle.WaitOne(1000))
  11.         {
  12.             throw new TimeoutException();
  13.         }
  14.         return methodDelegate.EndInvoke(result);
  15.     }
  16.     private object MyMethodInner(object param)
  17.     {
  18.         // Do the work
  19.     }
  20. \

We create a delegate to the method proper, which we can then invoke using BeginInvoke() on the delegate. This returns an IAsyncResult, from which we can use the AsyncWaitHandle to wait for the method to complete. The WaitOne method allows us to specify the timeout interval we want, and returns true if the method completes within that period. If it doesn’t, we raise a TimeoutException, otherwise we call EndInvoke() on the delegate and return the correct value.

If you read my previous post you’ll know what to expect with PostSharp in play…

  1. public class TimeoutWithPostSharp
  2. {
  3.     [Timeout(1000)]
  4.     public object MyMethod(object param)
  5.     {
  6.         // Do the work
  7.     }
  8. }

Again, all the plumbing is eliminated and you end up with clean code in which it’s obvious what’s going on. As with the Asynchronous attribute, this is implemented by inheriting the PostSharp.Laos.OnMethodInvocationAspect base class, which replaces the original method with a generated one that calls into your attribute. The code is straightforward, following the pattern shown in the first code snippet:

  1. [Serializable]
  2. public class TimeoutAttribute : OnMethodInvocationAspect
  3. {
  4.     /// <summary>
  5.     /// Initializes a new instance of the <see cref=”TimeoutAttribute”/> class.
  6.     /// </summary>
  7.     /// <param name=”timeoutMs”>
  8.     /// The timeout period in ms.
  9.     /// </param>
  10.     public TimeoutAttribute(int timeoutMs)
  11.     {
  12.         this.TimeoutMs = timeoutMs;
  13.     }
  14.     /// <summary>
  15.     /// The timeout period in ms.
  16.     /// </summary>
  17.     public int TimeoutMs { get; set; }
  18.     public override void OnInvocation(MethodInvocationEventArgs eventArgs)
  19.     {
  20.         Action proceedAction = eventArgs.Proceed;
  21.         IAsyncResult result = proceedAction.BeginInvoke(
  22.             null,
  23.             null);
  24.         bool completed = result.AsyncWaitHandle.WaitOne(this.TimeoutMs);
  25.         if (!completed)
  26.         {
  27.             throw new TimeoutException();
  28.         }
  29.         proceedAction.EndInvoke(result);
  30.     }
  31. }

The code for this aspect, along with some unit tests to prove I’m not making all this up, can be downloaded from Codeplex.


Tagged with: ,

Leave a Reply

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

You are commenting using your 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 )

Connecting to %s

%d bloggers like this: