ダウンしたリモートエンドポイントへの接続を定期的に確立しようとする再接続ロジックをいくつか書いています。基本的に、コードは次のようになります。
public void establishConnection() {
try {
this.connection = newConnection();
} catch (IOException e) {
// connection failed, try again.
try { Thread.sleep(1000); } catch (InterruptedException e) {};
establishConnection();
}
}
上記のようなコードを使用して、この一般的な問題を何度も解決しましたが、結果にはほとんど満足していません。この問題に対処するために設計されたデザインパターンはありますか?
チェックアウトする価値のあるライブラリの1つは Sarge です。これは、定義された計画に従って再試行を自動的に実行します。
恥知らずのプラグ:操作を再試行できるようにいくつかのクラスを実装しました。 ライブラリはまだ利用できませんが、 githubでフォーク。そして fork が存在します。
これにより、さまざまな柔軟な戦略を備えたRetryerを構築できます。例えば:
Retryer retryer =
RetryerBuilder.newBuilder()
.withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECOND))
.withStopStrategy(StopStrategies.stopAfterAttempt(3))
.retryIfExceptionOfType(IOException.class)
.build();
そして、Retryerでcallable(または複数のもの)を実行できます:
retryer.call(new Callable<Void>() {
public Void call() throws IOException {
connection = newConnection();
return null;
}
}
べき等リトライパターン を試すことができます。
AOPとJavaアノテーションを使用しています。 jcabi-aspects (I ' m開発者):
@RetryOnFailure(attempts = 3, delay = 1, unit = TimeUnit.SECONDS)
public void establishConnection() {
this.connection = newConnection();
}
追伸 Cactoos からRetryScalar
を試すこともできます。
Failsafe (ここの著者)を使用:
RetryPolicy retryPolicy = new RetryPolicy()
.retryOn(IOException.class)
.withMaxRetries(5)
.withDelay(1, TimeUnit.SECONDS);
Failsafe.with(retryPolicy).run(() -> newConnection());
注釈も魔法もありません。Springアプリである必要はありません。単純明快です。
私はこれが本当に好きですJava このブログ からの8つのコード)、クラスパスに追加のライブラリは必要ありません。
再試行クラスに関数を渡すだけです。
@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));
また、目的の操作に対してループを実行するラッパー関数を作成することもできます。ラッパー関数を作成すると、ループから抜け出します。
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");
}
spring-retry を試すことができます。きれいなインターフェイスがあり、使いやすいです。
例:
@Retryable(maxAttempts = 4, backoff = @Backoff(delay = 500))
public void establishConnection() {
this.connection = newConnection();
}
例外の場合、500msのバックオフポリシーでメソッドestablishConnection()の4倍まで再試行(呼び出し)します
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());
}
}
}
おかげで、
プラビーン・R.
再試行に特別なことは何もありません-このクラスを例として取り上げてください http://www.docjar.com/html/api/org/springframework/jms/listener/DefaultMessageListenerContainer.Java.html As you春の開発者でさえ、まだ再試行のためのコードを書いているのを見ることができます-行791 ...そのような特別なパターンはありません。
リソースに対処するためにアドバイスできるのは、Apache commons pool libraryを取得することです-これを確認してください http://commons.Apache.org/pool/apidocs/org/Apache/commons/pool/impl/GenericObjectPool.html にアクセスして http://commons.Apache.org/pool