为失败的逻辑进行 "重试 "的设计模式?[英] Design pattern for "retrying" logic that failed?

本文是小编为大家收集整理的关于为失败的逻辑进行 "重试 "的设计模式?的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我正在编写一些重新连接逻辑,以定期尝试建立与远程端点的连接.本质上,代码看起来像这样:

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

        establishConnection();
    }
}

我已经在许多情况下解决了与上述代码相似的代码的一般问题,但是我对结果不满意.是否有用于处理此问题的设计模式?

推荐答案

无耻的插头:我已经实施了一些类以重试操作. 库尚未提供,但是您可以https://github.com/ninja-squad/ninja-core/tree/tree/master/master/src/main/main/java/java/java/ninja_squad/core/core/core/core/core/core/core/重试github上的叉子 . 和 fork 存在.

它允许构建具有各种灵活策略的重试器.例如:

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

然后,您可以使用重试者执行可呼叫(或几个):

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

其他推荐答案

您可以尝试 idempotent retry taters .

.

在此处输入图像说明

其他推荐答案

我真的很喜欢此Java 8代码,来自此博客,您不需要classpath上的任何额外库.

您只需要将功能传递给重试类.

@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");
    }
}

并使用它:

new RetryCommand<>(5).run(() -> client.getThatThing(id));

本文地址:https://www.itbaoku.cn/post/627671.html

问题描述

I'm writing some reconnect logic to periodically attempt to establish a connection to a remote endpoint which went down. Essentially, the code looks like this:

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

        establishConnection();
    }
}

I've solved this general problem with code similar to the above on many occasions, but I feel largely unsatisfied with the result. Is there a design pattern designed for dealing with this issue?

推荐答案

Shameless plug: I have implemented some classes to allow retrying operations. The library is not made available yet, but you may fork it on github. And a fork exists.

It allows building a Retryer with various flexible strategies. For example:

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

And you can then execute a callable (or several ones) with the Retryer:

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

其他推荐答案

You could try the Idempotent Retry Pattern.

enter image description here

其他推荐答案

I really like this Java 8 code from this blog and you don't need any extra library on your classpath.

You only need to pass a function to the retry class.

@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");
    }
}

And to use it:

new RetryCommand<>(5).run(() -> client.getThatThing(id));