Add Timeouts to your methods with PostSharp

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:

publicclassTimeoutWithoutPostsharp

{

publicobject MyMethod(object param)

{

var methodDelegate = newFunc<object, object>(this.MyMethodInner);

var result = methodDelegate.BeginInvoke(

param,

null,

null);

if (!result.AsyncWaitHandle.WaitOne(1000))

{

thrownewTimeoutException();

}

return methodDelegate.EndInvoke(result);

}

privateobject MyMethodInner(object param)

{

// Do the work

}

\

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…

publicclassTimeoutWithPostSharp

{

[Timeout(1000)]

publicobject MyMethod(object param)

{

// Do the work

}

}

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:

[Serializable]

publicclassTimeoutAttribute : OnMethodInvocationAspect

{

///<summary>

/// Initializes a new instance of the <see cref=”TimeoutAttribute”/> class.

///</summary>

///<param name=”timeoutMs”>

/// The timeout period in ms.

///</param>

public TimeoutAttribute(int timeoutMs)

{

this.TimeoutMs = timeoutMs;

}

///<summary>

/// The timeout period in ms.

///</summary>

publicint TimeoutMs { get; set; }

publicoverridevoid OnInvocation(MethodInvocationEventArgs eventArgs)

{

Action proceedAction = eventArgs.Proceed;

IAsyncResult result = proceedAction.BeginInvoke(

null,

null);

bool completed = result.AsyncWaitHandle.WaitOne(this.TimeoutMs);

if (!completed)

{

thrownewTimeoutException();

}

proceedAction.EndInvoke(result);

}

}

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