如何捕获Guava重试器中的代码抛出的异常?

时间:2017-01-18 14:58:41

标签: java java-8 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

谢谢!

2 个答案:

答案 0 :(得分:1)

这是一个有点错误的模式。你说任何异常都可以重试。然后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);
}

答案 1 :(得分:0)

如果没有看到你的doStuff()或者至少知道它会引发什么样的例外,那就很难回答。

一般情况下,如果您Retryer认为每个Exception都不成功,它会重试并最终停止 - 但它会抓住任何 Throwable执行代码(见Retryer code,第162行)

解决方案是:

  • 如果doStuff()仅在导致停止重试的情况下抛出ArithmeticException,并且另一种异常标记为需要重试,则可以执行retryIfExceptoinOfType(OtherException.class) 。然后,根据文档the docs
  

<强>抛出:

     

java.util.concurrent.ExecutionException - 如果给定的callable抛出异常,并且拒绝谓词认为该尝试成功。原始异常包含在ExecutionException

call()将抛出一个ExecutionException,你可以在Retryer之外捕获并检查包装的异常。

  • 如果ArithmeticExcpetion全部doStuff()将抛出,并且这也表示重试者应该重试,那么您可以编写一个自定义StopStrategy,它会抛出ArithmeticExpcetion,它在Retryer中无处可寻。

但是我建议你完成重写你的代码,你的数据流似乎有点破碎。如果预期ArithmeticExpcetion(或实际上甚至是任何异常,在retryIf中指定Exception.class),则 也不应该意外,需要特殊处理。