improved retry test performance

This commit is contained in:
eeichinger
2009-09-23 15:46:34 +00:00
parent 95ade89c08
commit dbb3951e6b
4 changed files with 92 additions and 21 deletions

View File

@@ -53,12 +53,31 @@ namespace Spring.Aop.Support
/// <see cref="AttributeMatchMethodPointcutAdvisor"/> class
/// for the supplied <paramref name="advice"/>.
/// </summary>
/// <param name="advice"></param>
/// <param name="advice">the advice to apply if the pointcut matches</param>
public AttributeMatchMethodPointcutAdvisor(IAdvice advice)
{
this._advice = advice;
}
/// <summary>
/// Creates a new instance of the
/// <see cref="AttributeMatchMethodPointcutAdvisor"/> class
/// for the supplied <paramref name="advice"/>.
/// </summary>
/// <param name="attribute">
/// The <see cref="System.Attribute"/> to match.
/// </param>
/// <param name="inherit">
/// Flag that controls whether or not the inheritance tree of the
/// method to be included in the search for the <see cref="Attribute"/>?
/// </param>
/// <param name="advice">the advice to apply if the pointcut matches</param>
public AttributeMatchMethodPointcutAdvisor(Type attribute, bool inherit, IAdvice advice)
:base(attribute, inherit)
{
this._advice = advice;
}
/// <summary>
/// Is this advice associated with a particular instance?
/// </summary>

View File

@@ -41,6 +41,11 @@ namespace Spring.Aspects
[Serializable]
public class RetryAdvice : AbstractExceptionHandlerAdvice
{
///<summary>
///The type of the callback that is called for delaying retries.
///</summary>
public delegate void SleepHandler(TimeSpan duration);
private static readonly ILog log;
private static readonly TimeSpanConverter timeSpanConverter;
@@ -52,6 +57,8 @@ namespace Spring.Aspects
#region Fields
private SleepHandler sleepHandler;
[NonSerialized]
private RetryExceptionHandler retryExceptionHandler;
@@ -102,6 +109,21 @@ namespace Spring.Aspects
#endregion
/// <summary>
/// Creates a new RetryAdvice instance, using <see cref="Thread.Sleep(TimeSpan)"/> for delaying retries
/// </summary>
public RetryAdvice()
:this(new SleepHandler(Thread.Sleep))
{
}
/// <summary>
/// Creates a new RetryAdvice instance, using any arbitrary callback for delaying retries
/// </summary>
public RetryAdvice(SleepHandler sleepHandler)
{
this.sleepHandler = sleepHandler;
}
#region IMethodInterceptor implementation
@@ -158,7 +180,7 @@ namespace Spring.Aspects
{
log.Trace("Retrying " + invocation.Method.Name);
}
Sleep(retryExceptionHandler, callContextDictionary);
callContextDictionary["n"] = numAttempts;
Sleep(retryExceptionHandler, callContextDictionary, sleepHandler);
}
}
@@ -173,11 +195,11 @@ namespace Spring.Aspects
log.Debug("Invoked successfully after " + numAttempts + " attempt(s)");
return returnVal;
}
private static void Sleep(RetryExceptionHandler handler, IDictionary callContextDictionary)
private static void Sleep(RetryExceptionHandler handler, IDictionary callContextDictionary, SleepHandler sleepHandler)
{
if (handler.IsDelayBased)
Thread.Sleep(handler.DelayTimeSpan);
{
sleepHandler(handler.DelayTimeSpan);
}
else
@@ -186,19 +208,19 @@ namespace Spring.Aspects
{
IExpression expression = Expression.Parse(handler.DelayRateExpression);
object result = expression.GetValue(null, callContextDictionary);
decimal rounded = decimal.Round(d*1000,0);
int sleepInSeconds = decimal.ToInt32(rounded);
Thread.Sleep(sleepInSeconds);
decimal d = decimal.Parse(result.ToString());
decimal rounded = decimal.Round(d*1000,0);
TimeSpan duration = TimeSpan.FromMilliseconds(decimal.ToDouble(rounded));
sleepHandler(duration);
}
catch (InvalidCastException e)
log.Warn("Was not able to cast expression to decimal [" + handler.DelayRateExpression + "]. Sleeping for 1 second", e);
Thread.Sleep(1000);
{
log.Warn("Was not able to cast expression to decimal [" + handler.DelayRateExpression + "]. Sleeping for 1 second", e);
sleepHandler(new TimeSpan(0,0,1));
}
catch (Exception e)
log.Warn("Was not able to evaluate rate expression [" + handler.DelayRateExpression + "]. Sleeping for 1 second", e);
Thread.Sleep(1000);
{
log.Warn("Was not able to evaluate rate expression [" + handler.DelayRateExpression + "]. Sleeping for 1 second", e);
sleepHandler(new TimeSpan(0,0,1));
}
}

View File

@@ -21,6 +21,7 @@
#region Imports
using System;
using System.Collections;
using NUnit.Framework;
using Spring.Aop.Framework;
@@ -58,23 +59,28 @@ namespace Spring.Aspects
private static void InvokeOncePassOnceFail(bool useExceptionName, bool isDelay)
{
ITestRemoteService rs = GetRemoteService(2, useExceptionName, isDelay);
TestSleepHandler testSleepHandler = new TestSleepHandler();
ITestRemoteService rs = GetRemoteService(2, useExceptionName, isDelay, testSleepHandler);
rs.DoTransfer();
AssertSleepsAndReset(testSleepHandler, 2, isDelay);
rs = GetRemoteService(3, useExceptionName, isDelay);
rs = GetRemoteService(3, useExceptionName, isDelay, testSleepHandler);
try
{
rs.DoTransfer();
Assert.Fail("Should have failed.");
} catch (ArithmeticException)
{
// they maximum retry count is 3, thus only 2 sleep calls
AssertSleepsAndReset(testSleepHandler, 2, isDelay);
}
}
private static void InvokeOnceFailWithUnexceptedException(bool useExceptionName, bool isDelay)
{
ITestRemoteService rs = GetRemoteService(3, useExceptionName, isDelay);
TestSleepHandler testSleepHandler = new TestSleepHandler();
ITestRemoteService rs = GetRemoteService(3, useExceptionName, isDelay, testSleepHandler);
try
{
rs.DoTransfer2();
@@ -86,12 +92,40 @@ namespace Spring.Aspects
}
}
private static ITestRemoteService GetRemoteService(int numFailures, bool usingExceptionName, bool isDelay)
private static void AssertSleepsAndReset(TestSleepHandler testSleepHandler, int numFailures, bool isDelay)
{
Assert.AreEqual(numFailures, testSleepHandler.CalledTimeSpans.Count);
for(int i=0;i<numFailures;i++)
{
if (isDelay)
{
Assert.AreEqual(TimeSpan.FromSeconds(1), testSleepHandler.CalledTimeSpans[i]);
}
else
{
Assert.AreEqual(TimeSpan.FromSeconds(1 * (i + 1) + 0.5), testSleepHandler.CalledTimeSpans[i]);
}
}
testSleepHandler.CalledTimeSpans.Clear();
}
private class TestSleepHandler
{
public readonly ArrayList CalledTimeSpans = new ArrayList();
public void Sleep(TimeSpan duration)
{
CalledTimeSpans.Add(duration);
}
}
private static ITestRemoteService GetRemoteService(int numFailures, bool usingExceptionName, bool isDelay, TestSleepHandler testSleepHandler)
{
TestRemoteService remoteService = new TestRemoteService();
remoteService.NumFailures = numFailures;
ProxyFactory factory = new ProxyFactory(remoteService);
RetryAdvice retryAdvice = new RetryAdvice();
RetryAdvice retryAdvice = new RetryAdvice(new RetryAdvice.SleepHandler(testSleepHandler.Sleep));
if (usingExceptionName)
{
if (isDelay)

View File

@@ -176,10 +176,6 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\lib\Net\2.0\Common.Logging.dll</HintPath>
</Reference>
<Reference Include="nunit.core.interfaces, Version=2.4.1.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\lib\Net\2.0\nunit.core.interfaces.dll</HintPath>
</Reference>
<Reference Include="nunit.framework, Version=2.4.1.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\lib\Net\2.0\nunit.framework.dll</HintPath>