失败的"重试"逻辑的设计模式?

Naf*_*Kay 52 java io design-patterns

我正在编写一些重新连接逻辑,以定期尝试建立与远程端点的连接.从本质上讲,代码如下所示:

public void establishConnection() {
    try {
        this.connection = newConnection();
    } catch (IOException e) {
        // connection failed, try again.
        try { Thread.sleep(1000); } catch (InterruptedException e) {};

        establishConnection();
    }
}
Run Code Online (Sandbox Code Playgroud)

我已经在很多场合用类似上面的代码解决了这个一般问题,但我对结果感到很不满意.是否有设计模式来处理这个问题?

JB *_*zet 30

无耻的插件:我已经实现了一些类来允许重试操作. 该库尚未提供,但您可以在github上进行分叉.和叉子的存在.

它允许使用各种灵活的策略构建Retryer.例如:

Retryer retryer = 
    RetryerBuilder.newBuilder()
                  .withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECOND))
                  .withStopStrategy(StopStrategies.stopAfterAttempt(3))
                  .retryIfExceptionOfType(IOException.class)
                  .build();
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用重试程序执行可调用(或多个):

retryer.call(new Callable<Void>() {
    public Void call() throws IOException {
        connection = newConnection();
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 你(和我)忘了关闭一个括号:`withWaitStrategy(WaitStrategies.fixedWait(1,TimeUnit.SECONDS))`< - 这里有两个perentheses (2认同)

yeg*_*256 10

我正在使用AOP和Java注释.在jcabi-aspects中有一个现成的机制(我是开发人员):

@RetryOnFailure(attempts = 3, delay = 1, unit = TimeUnit.SECONDS)
public void establishConnection() {
  this.connection = newConnection();
}
Run Code Online (Sandbox Code Playgroud)

PS.您也可以尝试RetryScalar使用Cactoos.


Jon*_*han 6

使用故障安全(作者在这里):

RetryPolicy retryPolicy = new RetryPolicy()
  .retryOn(IOException.class)
  .withMaxRetries(5)
  .withDelay(1, TimeUnit.SECONDS);

Failsafe.with(retryPolicy).run(() -> newConnection());
Run Code Online (Sandbox Code Playgroud)

没有注释,没有魔法,不需要成为Spring应用程序,等等。简单明了。


db8*_*b80 5

您可以尝试spring-retry,它具有干净的界面并且易于使用。

例子:

 @Retryable(maxAttempts = 4, backoff = @Backoff(delay = 500))
 public void establishConnection() {
    this.connection = newConnection();
 } 
Run Code Online (Sandbox Code Playgroud)

在异常情况下,它将重试(调用)最多 4 次方法建立连接(),退避策略为 500 毫秒


Dhe*_*rik 5

我真的很喜欢此博客中的 Java 8代码,并且您的类路径上不需要任何额外的库。

您只需要将一个函数传递给retry类。

@Slf4j
public class RetryCommand<T> {

    private int maxRetries;

    RetryCommand(int maxRetries)
    {
        this.maxRetries = maxRetries;
    }

    // Takes a function and executes it, if fails, passes the function to the retry command
    public T run(Supplier<T> function) {
        try {
            return function.get();
        } catch (Exception e) {
            log.error("FAILED - Command failed, will be retried " + maxRetries + " times.");
            return retry(function);
        }
    }

    private T retry(Supplier<T> function) throws RuntimeException {

        int retryCounter = 0;
        while (retryCounter < maxRetries) {
            try {
                return function.get();
            } catch (Exception ex) {
                retryCounter++;
                log.error("FAILED - Command failed on retry " + retryCounter + " of " + maxRetries, ex);
                if (retryCounter >= maxRetries) {
                    log.error("Max retries exceeded.");
                    break;
                }
            }
        }
        throw new RuntimeException("Command failed on all of " + maxRetries + " retries");
    }
}
Run Code Online (Sandbox Code Playgroud)

并使用它:

new RetryCommand<>(5).run(() -> client.getThatThing(id));
Run Code Online (Sandbox Code Playgroud)