improved retry test performance
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user