简体   繁体   中英

How do I catch the exception thrown by the code inside a Guava retryer?

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:

  • If your 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 an ExecutionException .

call() will throw an ExecutionException that you can catch outside of the Retryer and inspect the wrapped Exception.

  • If 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM