【问题标题】:Java 8 generic Retry if specific exception如果特定异常,Java 8 通用重试
【发布时间】:2017-02-14 16:26:46
【问题描述】:

我发现自己写了很多看起来像这样的重试循环

    int triesRemaining = 3;

    while (triesRemaining > 0) {
        try {
            <MY FUNCTION CALL>
            LOGGER.info("success");
            break;
        } catch (Exception e) {
            if (e.getCause() instanceof SocketTimeoutException) {
                triesRemaining--;
                LOGGER.info(e.getMessage() + " trying again. Tries Remaining: " + triesRemaining);
            } else {
                LOGGER.error(e.getMessage(), e);
                return;
            }
        }
    }
    if (triesRemaining == 0) {
        LOGGER.error("Failed over too many times");
    }

我想编写一个接受 Lambda 并仅重试特定错误的通用函数(在上述情况下为 SocketTimeoutException)。我见过一些接受Runnable 的函数,这很好,但它们似乎不允许限制特定的例外。

有什么建议吗?

【问题讨论】:

    标签: java spring exception-handling


    【解决方案1】:

    查看Failsafe:

    RetryPolicy retryPolicy = new RetryPolicy()
      .retryOn(SocketTimeoutException.class)
      .withMaxRetries(3);
    
    Failsafe.with(retryPolicy)
      .onRetry((c, f, ctx) -> log.warn("Failure #{}. Retrying.", ctx.getExecutions()))
      .onFailure(e -> LOGGER.error(e.getMessage(), e))
      .run(() -> myFunctionCall());
    

    【讨论】:

      【解决方案2】:

      让这个函数接受Runnable 参数然后在&lt;MY FUNCTION CALL&gt; 中运行它有什么问题?

      public static void retry(Runnable r) {
            // ...
            while (triesRemaining > 0) {
              try {
                  r.run();
                  LOGGER.info("success");
                  break;
              } 
            // ...
      }
      

      然后调用它(如果您愿意 - 使用 lambda):

          retry(() -> {
              connectToServer();
              // todo what-ever-you-want
          });
      

      【讨论】:

      • 我只想捕获特定的异常
      • TBH 我不明白这句话与我的建议有什么关系:) 我刚刚省略了你代码的其余部分,我将其标记为“// ...”。
      • 因为我希望函数一般接受异常类,但我遇到了麻烦。但我查看了 guava-retrying 并看到 Class&lt;? extends Throwable&gt; 这是我的问题的解决方案
      • 我还是不明白你的意思:-D
      • 函数应该有签名void retry(Runnable run, Class&lt;? extends Throwable&gt; exception, int numTries)。但我们在这里都很好。
      【解决方案3】:

      好吧,它已经完成了。它还接受您要重试的异常列表。它还提供线性/指数重试策略。 看看https://github.com/rholder/guava-retrying

      readme 中的一个简单示例,您可以编写和使用重试器,例如:-

      Callable<Boolean> callable = new Callable<Boolean>() {
      public Boolean call() throws Exception {
          return true; // do something useful here
      }};
      
      Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
          .retryIfResult(Predicates.<Boolean>isNull())
          .retryIfExceptionOfType(IOException.class)
          .retryIfRuntimeException()
          .withStopStrategy(StopStrategies.stopAfterAttempt(3))
          .build();
      
      try {
        retryer.call(callable);
      } catch (RetryException e) {
          e.printStackTrace();
      } catch (ExecutionException e) {
          e.printStackTrace();
      }
      

      【讨论】:

        【解决方案4】:

        看看 org.springframework.retry

        有一个注解@Retryable 对应你的需要。可以指定重试的异常类型,配置尝试次数等...

        【讨论】:

        • 亲爱的 OP,将来在标签中提及您正在使用的 spring 框架不会更糟
        【解决方案5】:

        我相信您正在寻找基于纯 Java 的解决方案。基于假设,我会说 Java 8 使用功能接口,一个具有单一抽象方法的接口。我会创建一个新的 RetryCommand 类,它有一个接收函数的 run 方法。

        【讨论】:

          猜你喜欢
          • 2021-10-29
          • 1970-01-01
          • 2023-02-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多