I have a Guava retryer around some code:
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);
}
Let's say doStuff()
throws an ArithmeticException
. How do I catch that outside the retryer.call()
?
So the retryer will try a couple times, fail, and enter into the catch (ExecutionException | RetryException e)
block. How would I retrieve the ArithmeticException
inside there?
Thanks!
This is a bit of a faulty pattern. You say that any exception is ok to retry. An ArithmeticException
will then be ok to retry. This is not what you want.
This is how retries should be implemented. Note the comment on the second line.
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);
}
}
Then when you actually call doStuff
:
try {
doStuff();
} catch(ArithmeticException e) {
System.err.println("Arithmetic exception caught:");
e.printStackTrace(System.err);
}
Without seeing your doStuff()
or at least knowing what kinds of Exceptions it throws it's hard to answer.
In general, if you have the Retryer
consider every Exception
unsuccessful, it will retry and eventuelly stop - but it catches any Throwable
thrown inside the executed code (see Retryer code , line 162)
The solution is either:
doStuff()
only throws an ArithmeticException
in those cases that result in stopping the Retryer, and that a different kind of Exception marks that a retry is necessary, you can do retryIfExceptoinOfType(OtherException.class)
. Then, according to the docs 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()
will throw an ExecutionException
that you can catch outside of the Retryer and inspect the wrapped Exception.
ArithmeticExcpetion
is all doStuff()
will throw, and that also indicates that the Retryer should retry, then you can write a custom StopStrategy
that throw an ArithmeticExpcetion
, it is catched nowhere in the Retryer. However I advise you to completele rewrite your code, your data flow seems a bit broken. If an ArithmeticExpcetion
(or actually even any Exception, as you specify Exception.class
in the retryIf ) is to be expected, it should not also be unexpected and need special handling.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.