2011-01-19 17 views
20

私は、何らかの形のバックオフ・ビフォー・リトライ・ロジックを使用して失敗すると、何度もタスクを再試行する必要がある状況が数多くあります。通常、例外がスローされた場合、タスクは最大再試行回数まで再試行する必要があります。タスクの再試行

私はこれをかなり一般的に行うために何かを簡単に書くことができますが、誰もがこのフレームワークを推薦できるかどうか疑問に思っていました。私が見つけることができる唯一の事は:Ant Retryですが、自分のアプリケーションでAntタスクを直接使用したくありません。

おかげ

+0

どのようなタスクをやり直したいですか? – fmucar

+5

@fatih - 問題はありません。タスクの再試行は抽象的な概念です。 – Scruffers

+0

興味深いことに、再試行するアクションをいくつかのクラスで再試行するように誰もが思っています。私はむしろ 'boolean shallWeRetryOnceMore()'メソッドをバックオフ/リトライ戦略マネージャーとして実装し、呼び出されたときすぐに 'false'を返すか、バックオフアルゴリズムに応じて時間を待ってからtrueを返します。 – Harald

答えて

15

RetriableTasksは、この投稿に記載されているとおりに使用できます。Retrying Operations in Java必要に応じて、待機アルゴリズムを簡単に変更することができます。

サンプルコード:

//creates a task which will retry 3 times with an interval of 5 seconds 
RetriableTask r = new RetriableTask(3, 5000, new Callable(){ 
    public Object call() throws Exception{ 
     //put your code here 
    } 
}); 
r.call(); 
0

あなたはQuartzを使用することができます。を参照してくださいthisスタックオーバーフローの答え。

1

これをコードベースから除外する1つのオプションは、アプリケーションのコンポーネント間でコマンドパターンを使用することです。 ビジネスメソッドの呼び出しをオブジェクトに変換すると、呼び出しを簡単に手渡すことができ、抽象的なRetryHandlerでコマンドを受け取り、再試行することができます。これは実際の呼び出しから独立していて、再利用可能でなければなりません。

+0

ありがとうございましたJochen、これは、タスクがRunnableかCallableのいずれかのインスタンスなので、私が持っているものです。私は、リトライロジックやバックオフアルゴリズムの種類を指定するなどのオプションを提供するフレームワークであることを期待していました。 – Scruffers

+0

私は気付いていません。それはかなり珍しいですが、私は同意します。我々は、ほとんどの場合、永続化レイヤと通信するときに楽観的な例外に対処するために再試行を使用します。 –

8

あなたが春を使用する場合:

//import the necessary classes 
import org.springframework.batch.retry.RetryCallback; 
import org.springframework.batch.retry.RetryContext; 
import org.springframework.batch.retry.backoff.ExponentialBackOffPolicy; 
import org.springframework.batch.retry.policy.SimpleRetryPolicy; 
import org.springframework.batch.retry.support.RetryTemplate; 
... 

// create the retry template 
final RetryTemplate template = new RetryTemplate(); 
template.setRetryPolicy(new SimpleRetryPolicy(5)); 
final ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy(); 
backOffPolicy.setInitialInterval(1000L); 
template.setBackOffPolicy(backOffPolicy); 

// execute the operation using the retry template 
template.execute(new RetryCallback<Remote>() { 
    @Override 
    public Remote doWithRetry(final RetryContext context) throws Exception { 
    return (Remote) Naming.lookup("rmi://somehost:2106/MyApp"); 
    } 
}); 

Original blog post

+1

より具体的には、Spring Batchを使用していて、依存関係が必要な場合。 – Jonathan

0

を、私はあなたが持つ任意のコーラブルを再試行することができ、かなり柔軟な再試行ユーティリティhere

を実装しています:

public static <T> T executeWithRetry(final Callable<T> what, final int nrImmediateRetries, 
     final int nrTotalRetries, final int retryWaitMillis, final int timeoutMillis, 
     final Predicate<? super T> retryOnReturnVal, final Predicate<Exception> retryOnException) 

最大タイムアウトを指定して、即時遅延リトライを行い、結果または例外に基づいて判断を再試行します。

多かれ少なかれ柔軟性があるこの機能のいくつかの他のバージョンがあります。

私はまた、注釈RetryRetry Aspect

9

Failsafeをチェックして適用することができ様相を書かれています。これは、再試行を実行するためのシンプルな、ゼロ依存ライブラリだし、同期および非同期の再試行をサポートし、その他のJava 8の統合、イベントリスナー、他の非同期APIとの統合、:

RetryPolicy retryPolicy = new RetryPolicy() 
    .retryOn(ConnectException.class, SocketException.class); 
    .withMaxRetries(3); 

Connection connection = Failsafe.with(retryPolicy).get(() -> connect()); 

は、はるかに簡単に取得していません。

0

私はすでに答えが1つありますが、それは3年前のことです。私はそれを追加しなければなりません。今、私は絶対的な愛guava-retryingプロジェクトを追加します。 それは依存としてGuavaを持っていませんが、私は著者がこのプロジェクトに触発されたと思います 。コードを見せてあげましょう。

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(); 
} 
+2

もちろんGuavaは依存関係です:https://github.com/rholder/guava-retrying/blob/master/build.gradle#L84そうでなければ、コード例はコンパイルされません。 – Jonathan

+1

固定、ありがとう@ジョナサン – mulya

+0

これはきちんとしていて、StopStrategiesの抽象化はクールです。 Tho、私はこれが一定の時間間隔での定期的なリドライや指数関数的なバックオフ、あるいは互い違いのような異なるリトライ戦略を実装する上で(またはまったく)うまくいくかどうかは不明です。 – g7p

4

あなたは春を使用している場合は、それがSpring Retryライブラリを使用して非常にシンプルなです。

さて、春の再試行は、個々のライブラリー(以前それは春のバッチの一部であった)フレームワークです。

ステップ1:スプリングリトライの依存性を追加します。

<dependency> 
    <groupId>org.springframework.retry</groupId> 
    <artifactId>spring-retry</artifactId> 
    <version>1.1.2.RELEASE</version> 
</dependency> 

ステップ2:はあなた@Configurationクラスのいずれかにアプリケーションのmain()メソッドが含まれている、あなたのクラスに@EnableRetry注釈を追加します。

ステップ3:あなたは、例外の場合には、再び呼び出す/再試行したいあなた方法@Retryable注釈を追加します。

@Retryable(maxAttempts=5,backoff = @Backoff(delay = 3000)) 
public void retrySomething() throws Exception{ 
    logger.info("printSomething{} is called"); 
    throw new SQLException(); 
} 

この@Retryable注釈はretrySomething() 5回(含む第一の障害)を呼び出し/再試行されます。

現在のスレッドは、次の再試行の間に3000秒または3秒を待機します。