如何捕获 Guava 重试器内部代码抛出的异常?
How do I catch the exception thrown by the code inside a Guava retryer?
我有一个围绕某些代码的 Guava 重试器:
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
.retryIfExceptionOfType(Exception.class)
.withStopStrategy(MoreStopStrategies.liveStopAfterAttempt(retries))
.withWaitStrategy(MoreWaitStrategies.liveExponentialWait(TimeUnit.MILLISECONDS, retrySleep, TimeUnit.MILLISECONDS))
.build();
try {
retryer.call(() -> {
return doStuff();
});
} catch (ExecutionException | RetryException e) {
throw Throwables.propagate(e);
}
假设 doStuff()
抛出一个 ArithmeticException
。我如何在 retryer.call()
之外捕获它?
因此重试器将尝试几次,失败并进入 catch (ExecutionException | RetryException e)
块。我将如何检索其中的 ArithmeticException
?
谢谢!
这是一个有点错误的模式。你说任何异常都可以重试。然后 ArithmeticException
就可以重试了。这不是你想要的。
这就是重试的实施方式。注意第二行的注释。
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
// .retryIfExceptionOfType(Exception.class)
.withStopStrategy(MoreStopStrategies.liveStopAfterAttempt(retries))
.withWaitStrategy(MoreWaitStrategies.liveExponentialWait(TimeUnit.MILLISECONDS, retrySleep, TimeUnit.MILLISECONDS))
.build();
void doStuff() {
try {
retryer.call(() -> {
doRealStuff();
});
} catch (RetryException e) {
throw new RuntimeException("Call never succeeded", e);
} catch (ExecutionException e) {
Throwables.propagateIfPossible(e.getCause(), ArithmeticException.class);
throw new RuntimeException("Unexpected", e);
}
}
然后当你实际调用 doStuff
:
try {
doStuff();
} catch(ArithmeticException e) {
System.err.println("Arithmetic exception caught:");
e.printStackTrace(System.err);
}
没有看到您的 doStuff()
或至少不知道它抛出的异常类型很难回答。
一般来说,如果您 Retryer
考虑每个 Exception
不成功,它会重试并最终停止 - 但它会捕获 any Throwable
抛入执行的代码中(参见 Retryer code,第 162 行)
解决方案是:
- 如果您的
doStuff()
仅在那些导致重试器停止的情况下抛出 ArithmeticException
,并且另一种异常表明需要重试,您可以 retryIfExceptoinOfType(OtherException.class)
.然后,根据文档 the docs
Throws:
java.util.concurrent.ExecutionException
- if the given callable throws an exception, and the rejection predicate considers the attempt as successful. The original exception is wrapped into an ExecutionException
.
call()
将抛出一个 ExecutionException
,您可以在 Retryer 外部捕获它并检查包装的异常。
- 如果
ArithmeticExcpetion
是全部 doStuff()
将抛出,并且这也表明 Retryer 应该重试,那么您可以编写一个自定义 StopStrategy
来抛出 ArithmeticExpcetion
, 它在重试器中无处可寻。
但是我建议您完全重写您的代码,您的数据流似乎有点损坏。如果 ArithmeticExpcetion
(或者实际上什至是 any 异常,正如您在 retryIf 中指定的 Exception.class
)是预期的,它不应该 also 出乎意料,需要特殊处理。
我有一个围绕某些代码的 Guava 重试器:
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
.retryIfExceptionOfType(Exception.class)
.withStopStrategy(MoreStopStrategies.liveStopAfterAttempt(retries))
.withWaitStrategy(MoreWaitStrategies.liveExponentialWait(TimeUnit.MILLISECONDS, retrySleep, TimeUnit.MILLISECONDS))
.build();
try {
retryer.call(() -> {
return doStuff();
});
} catch (ExecutionException | RetryException e) {
throw Throwables.propagate(e);
}
假设 doStuff()
抛出一个 ArithmeticException
。我如何在 retryer.call()
之外捕获它?
因此重试器将尝试几次,失败并进入 catch (ExecutionException | RetryException e)
块。我将如何检索其中的 ArithmeticException
?
谢谢!
这是一个有点错误的模式。你说任何异常都可以重试。然后 ArithmeticException
就可以重试了。这不是你想要的。
这就是重试的实施方式。注意第二行的注释。
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
// .retryIfExceptionOfType(Exception.class)
.withStopStrategy(MoreStopStrategies.liveStopAfterAttempt(retries))
.withWaitStrategy(MoreWaitStrategies.liveExponentialWait(TimeUnit.MILLISECONDS, retrySleep, TimeUnit.MILLISECONDS))
.build();
void doStuff() {
try {
retryer.call(() -> {
doRealStuff();
});
} catch (RetryException e) {
throw new RuntimeException("Call never succeeded", e);
} catch (ExecutionException e) {
Throwables.propagateIfPossible(e.getCause(), ArithmeticException.class);
throw new RuntimeException("Unexpected", e);
}
}
然后当你实际调用 doStuff
:
try {
doStuff();
} catch(ArithmeticException e) {
System.err.println("Arithmetic exception caught:");
e.printStackTrace(System.err);
}
没有看到您的 doStuff()
或至少不知道它抛出的异常类型很难回答。
一般来说,如果您 Retryer
考虑每个 Exception
不成功,它会重试并最终停止 - 但它会捕获 any Throwable
抛入执行的代码中(参见 Retryer code,第 162 行)
解决方案是:
- 如果您的
doStuff()
仅在那些导致重试器停止的情况下抛出ArithmeticException
,并且另一种异常表明需要重试,您可以retryIfExceptoinOfType(OtherException.class)
.然后,根据文档 the docs
Throws:
java.util.concurrent.ExecutionException
- if the given callable throws an exception, and the rejection predicate considers the attempt as successful. The original exception is wrapped into anExecutionException
.
call()
将抛出一个 ExecutionException
,您可以在 Retryer 外部捕获它并检查包装的异常。
- 如果
ArithmeticExcpetion
是全部doStuff()
将抛出,并且这也表明 Retryer 应该重试,那么您可以编写一个自定义StopStrategy
来抛出ArithmeticExpcetion
, 它在重试器中无处可寻。
但是我建议您完全重写您的代码,您的数据流似乎有点损坏。如果 ArithmeticExpcetion
(或者实际上什至是 any 异常,正如您在 retryIf 中指定的 Exception.class
)是预期的,它不应该 also 出乎意料,需要特殊处理。