要测试当某个函数抛出异常时,会重试X次。
import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
class Retry {
public Retryer<UserData> getRetryer() {
return RetryerBuilder.<UserData>newBuilder()
.retryIfException()
.withWaitStrategy(waitStrategy()) //exponential with 3 attempts
.withStopStrategy(stopStrategy())
.withAttemptTimeLimiter(attemptTimeLimiter())
.build();
}
}
class UserClass
{
private final externalTeamLibrary; //and a constructor accepting it
public publishSync(Some inputs, Retry retryParameters)
{
Callable<UserData> publishCallable =
() -> publishAsync(Some inputs) //returns Future object
.get(retryParameters.callTimeOutInMs(), TimeUnit.MILLISECONDS);
return retryParameters.getRetryer().call(publishCallable);
}
public Future<FutureData> publishAsync(Some inputs)
{
return externalTeamLibrary.send(obj1, obj2); //returns Future object
}
}
测试代码
@Test
public voide testFunction()
{
//real objects
Retry realRetryInstance = // a way to get one
//mocks
ExternalTeamLibraryClass externalTeamLibraryMock= createMock(ExternalTeamLibraryClass.class);
//expectations and return values
EasyMock.expect(externalTeamLibraryMock.send(anyObject(), anyObject()))
.andThrow(new InterruptException("test1"))
.times(3);
EasyMock.replay(externalTeamLibraryMock);
UserClass user = new UserClass(externalTeamLibraryMock, other stuff);
user.publishSync(someRealInputs, realRetryInstance);
//verify all mocks used
EasyMock.verify(externalTeamLibraryMock);
}
在显式调用publishSync并使externalTeamLibrary.send()抛出异常时,我希望真正的重试对象重试&#39; publishAsync()。重试限制是3,所以我希望对externalTeamLibrary.send()进行三次调用。
但我得到以下错误。
[junit] Testcase: testFunction: Caused an ERROR
[junit] Retrying failed to complete successfully after 1 attempts.
[junit] com.github.rholder.retry.RetryException: Retrying failed to complete successfully after 1 attempts.
[junit] at com.github.rholder.retry.Retryer.call(Retryer.java:181)
[junit] at UserClass.publish
[junit] at TestClass.testFunction
[junit] Caused by: org.apache.kafka.common.errors.InterruptException: test1
[junit] at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:46)
[junit] at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:94)
[junit] at org.easymock.internal.ClassProxyFactory$MockMethodInterceptor.intercept(ClassProxyFactory.java:97)
[junit] at externalTeamLibrary$$EnhancerByCGLIB$$f53a1a7e.send(<generated>)
[junit] at UserClass.publishAsync(line:175)
[junit] at UserClass.lambda$publish$1(lineZ:209)
[junit] at com.github.rholder.retry.AttemptTimeLimiters$NoAttemptTimeLimit.call(AttemptTimeLimiters.java:78)
[junit] at com.github.rholder.retry.Retryer.call(Retryer.java:160)
[junit] Caused by: java.lang.InterruptedException
[junit] at org.apache.kafka.common.errors.InterruptException.<init>(InterruptException.java:35)
[junit] at TestClass.testFunction
在我抛出InterruptException
的行上发生错误只是顿悟了。
如果我的外部库模拟抛出org.apache.kafka.common.errors.InterruptException
以外的其他内容,则重试失败并显示正确的消息重试3次后无法成功完成。。
但是当我的模拟抛出InterruptException
时,第一次尝试后重试失败。两种情况下的失败点都不同。 In the guava retry code。
第174行是用于快乐的情况,其中使用了停止策略。第181行是负面情况,其中InterruptException导致InterruptedException!
This link表明kafka的InterruptException只是InterruptedException的包装器。 所以真正的问题是如何成功重试它。如果线程在尝试执行任务时被中断,我觉得这是应该重试的,因为我们不确定它是不可恢复的。