68

ダウンしたリモートエンドポイントへの接続を定期的に確立しようとする再接続ロジックを作成しています。基本的に、コードは次のようになります。

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

        establishConnection();
    }
}

私はこの一般的な問題を上記と同様のコードで何度も解決しましたが、結果にはほとんど満足できません。この問題に対処するために設計されたデザインパターンはありますか?

4

12 に答える 12

31

恥知らずなプラグイン:操作を再試行できるようにいくつかのクラスを実装しました。ライブラリはまだ利用できませんが、githubでフォークすることができます。そして、フォークが存在します。

これにより、さまざまな柔軟な戦略でリトライアーを構築できます。例えば:

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

そして、Retryerを使用して呼び出し可能(または複数の呼び出し可能)を実行できます。

retryer.call(new Callable<Void>() {
    public Void call() throws IOException {
        connection = newConnection();
        return null;
    }
}
于 2012-07-27T17:45:33.693 に答える
29

べき等再試行パターンを試すことができます。

ここに画像の説明を入力してください

于 2012-07-27T17:26:36.607 に答える
15

私はこのブログのこのJava8コードが本当に好きで、クラスパスに追加のライブラリは必要ありません。

関数を再試行クラスに渡すだけで済みます。

@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));
于 2018-05-25T17:03:31.487 に答える
12

フェイルセーフの使用(作成者はこちら):

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

Failsafe.with(retryPolicy).run(() -> newConnection());

アノテーションや魔法はなく、Springアプリなどである必要はありません。単純明快です。

于 2016-07-26T23:01:43.800 に答える
11

AOPとJavaのアノテーションを使用しています。jcabi-aspectsには既成のメカニズムがあります(私は開発者です):

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

ps。CactoosRetryScalarから試すこともできます。

于 2013-02-03T08:39:14.860 に答える
5

春のリトライを試すことができます、それはきれいなインターフェースを持っていて、それは使いやすいです。

例:

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

例外の場合、500msのバックオフポリシーでメソッドestablishConnection()を最大4回再試行(呼び出し)します

于 2016-02-19T22:14:27.013 に答える
4

チェックアウトする価値のあるライブラリの1つは、定義された計画に従って自動的に再試行を実行するSargeです。

于 2012-08-08T05:10:59.107 に答える
3

また、目的の操作をループするだけのラッパー関数を作成し、実行されるとループから抜け出すこともできます。

public static void main(String[] args) {
    retryMySpecialOperation(7);
}

private static void retryMySpecialOperation(int retries) {
    for (int i = 1; i <= retries; i++) {
        try {
            specialOperation();
            break;
        }
        catch (Exception e) {
            System.out.println(String.format("Failed operation. Retry %d", i));
        }
    }
}

private static void specialOperation() throws Exception {
    if ((int) (Math.random()*100) % 2 == 0) {
        throw new Exception("Operation failed");
    }
    System.out.println("Operation successful");
}
于 2019-02-27T16:07:09.177 に答える
1

Java 8を使用している場合、これが役立つ場合があります。

import java.util.function.Supplier;

public class Retrier {
public static <T> Object retry(Supplier<T> function, int retryCount) throws Exception {
     while (0<retryCount) {
        try {
            return function.get();
        } catch (Exception e) {
            retryCount--;
            if(retryCount == 0) {
                throw e;
            }
        }
    }
    return null;
}

public static void main(String[] args) {
    try {
        retry(()-> {
            System.out.println(5/0);
            return null;
        }, 5);
    } catch (Exception e) {
        System.out.println("Exception : " + e.getMessage());
    }
}
}

ありがとう、

PraveenR。

于 2018-04-12T17:52:09.533 に答える
0

再試行に特別なことは何もありません-このクラスを例として取り上げてくださいhttp://www.docjar.com/html/api/org/springframework/jms/listener/DefaultMessageListenerContainer.java.htmlご覧の とおり、春の開発者でさえまだ書いています再試行のコード-791行目...そのような特別なパターンAFAIKはありません。

リソースを処理するためにアドバイスできるのは、Apache Commonsプールライブラリを使用することです。このhttp://commons.apache.org/pool/apidocs/org/apache/commons/pool/impl/GenericObjectPool.htmlを確認し、 http:/にアクセスしてください。 /commons.apache.org/pool

于 2012-07-27T17:29:29.380 に答える
0

私はretry4jライブラリを使用しています。テストコードの例:

public static void main(String[] args) {
    Callable<Object> callable = () -> {
        doSomething();
        return null;
    };

    RetryConfig config = new RetryConfigBuilder()
            .retryOnAnyException()
            .withMaxNumberOfTries(3)
            .withDelayBetweenTries(5, ChronoUnit.SECONDS)
            .withExponentialBackoff()
            .build();

    new CallExecutorBuilder<>().config(config).build().execute(callable);
}

public static void doSomething() {
    System.out.println("Trying to connect");
    // some logic
    throw new RuntimeException("Disconnected"); // init error
    // some logic
}
于 2019-12-06T09:38:21.763 に答える
0

再試行を実行する別のアプローチを次に示します。ライブラリ、注釈、追加の実装はありません。java.util.concurrent.TimeUnitをインポートします。

public static void myTestFunc() {
        boolean retry = true;
        int maxRetries = 5;   //max no. of retries to be made
        int retries = 1;
        int delayBetweenRetries = 5;  // duration  between each retry (in seconds)
        int wait = 1;
    do {
        try {
            this.connection = newConnection();
            break;
        }
        catch (Exception e) {
            wait = retries * delayBetweenRetries;
            pause(wait);
            retries += 1;
            if (retries > maxRetries) {
                retry = false;
                log.error("Task failed on all of " + maxRetries + " retries");
            }
        }
    } while (retry);

}

public static void pause(int seconds) {
    long secondsVal = TimeUnit.MILLISECONDS.toMillis(seconds);

    try {
        Thread.sleep(secondsVal);
    }
    catch (InterruptedException ex) {
        Thread.currentThread().interrupt();
    }
}

}

于 2021-05-09T19:45:08.523 に答える