SpringRetryを使用したリトライ処理の追加方法

依存関係の追加

SpringRetryを追加する。
リトライ処理の実装にはAOPを使用しているため、AOPが使用できるように別途モジュールも追加する。

dependencies {
  // Spring Retry
  implementation 'org.springframework.retry:spring-retry'
  // Spring Boot Starter AOP
  implementation 'org.springframework.boot:spring-boot-starter-aop'
}

リトライを有効化する

アプリでキャッシュ機能を有効化するためにMainクラスに「@EnableRetryアノテーションを付与する。

Mainクラスのほかに、「@Configurationアノテーションが付与されているJavaConfigクラスに付与しても良い。
アプリが特定の機能を使用する際のみリトライを有効化したい場合などに使用する。

import org.springframework.retry.annotation.EnableRetry;

@SpringBootApplication
@EnableRetry
public class WebappApplication {

    /**
     * Webアプリケーションを起動する。<br>
     *
     * @param args
     *            起動時引数
     */
    public static void main(String[] args) {
        SpringApplication.run(WebappApplication.class, args);
    }
}

例外発生時にリトライするメソッドの実装

例外発生時にリトライしたいメソッドに「@Retryableアノテーションを付与する。
また、リトライしたいメソッドを含むクラスは、プロジェクトで使用する際にはDIコンテナに登録する。
(※SpringBootでのリトライはAOPの機能を利用して実装されているため)

import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;

@Component
public class RetrySample {
    
    private SampleDao dao;
    
    public RetrySample(SampleDao dao) {
        this.dao = dao;
    }
    
    @Retryable(value = { OptimisticLockingFailureException.class }, maxAttempts = 4, backoff = @Backoff(3000))
    public void retry(int num) {
        dao.updateNumver(num);
    }
}

@Retryableの属性について

recover

リカバーに使用するメソッド名。
メソッドには別途「@Recoverアノテーションを付与する必要がある。

interceptor

リトライ対象のメソッドに適用するインターセプターのbean名。

value

リトライ対象とする例外クラス。include属性と一緒。
デフォルトは空であり、あらゆる例外発生時にメソッドがリトライされる。

include

リトライ対象とする例外クラス。
デフォルトは空であり、あらゆる例外発生時にメソッドがリトライされる。

exclude

リトライ対象外とする例外クラス。
デフォルトは空であり、あらゆる例外発生時にメソッドがリトライされる。

include属性が空で、exclude属性に何らかの例外クラスが指定されている場合、
exclude属性に指定されている例外クラス以外の例外スロー時にメソッドがリトライされる。

label

レポート用の一意のラベル。

stateful

リトライがステートフルであることを示すフラグ。
trueの場合、例外は再スローされるが、同じ引数の後続の呼び出しに、同一の再試行ポリシーが適用される。
falseの場合、リトライ対象の例外は再スローされない。
デフォルト:false

maxAttempts

リトライの最大試行回数。(回数には最初の失敗を含む)
デフォルト:3

maxAttemptsExpression

最大試行回数 (最初の失敗を含む) を評価する式。

backoff

リトライ時のバックオフポリシーを指定する。
特に指定しない場合、シンプルなリトライ処理が適用される。

exceptionExpression

SimpleRetryPolicy.canRetry() が true を返した後に評価される式を指定する。
この式は、条件付きでリトライを抑制するために使用することが想定される。

この式は例外がスローされた後にのみ呼び出しされる。
式の評価対象は最後にスローされたThrowableとなり、コンテキスト内の他のbeanも参照することができる。

listeners

Springcontextで定義されているデフォルトのリスナーの代わりに使用する再試行リスナーのbean名。

@Backoffの属性について

バックオフポリシーの定義を行うためのアノテーション
以下の特徴がある:

  • 明示的な設定が記載されなかった場合:リトライ間隔は固定で「1000ミリ秒」となる
  • delay属性のみ設定されている場合:リトライ間隔はdelay属性で指定された値で固定となる
  • delay属性とmaxDelay属性が設定されている場合:リトライ間隔は、delay属性とmaxDelay属性に指定された2つの値の間で一様に分散した値となる
  • delay属性とmaxDelay属性、multiplier属性が設定されている場合:リトライ間隔はmaxDelay属性に指定された値まで指数関数的に増加していく
  • delay属性とmaxDelay属性、multiplier属性、random属性がtrueとなっている場合、指数関数の乗数は各リトライ試行に対して[1, multiplier-1]の一様分布から選択される。

※「○○Expression」系の属性は、「○○」の属性を文字列で指定するためのものなので、基本的には使用しなくてもOK

value

delay()属性と同じ。
delay属性の値が0でない場合、この属性に設定した値は無視される。
delay属性の値が0の場合はこの属性の値が使用される。
デフォルト:1000

delay

リトライ間隔。
リトライ間隔の決定方式によって、この値の利用方法が異なり、
指数関数の場合は初期値、一様関数の場合は最小値として利用される。

この属性の値が0の場合はvalue属性の値が使用される。
0以外の値が指定されている場合は、この属性の値が使用される。
デフォルト:0

maxDelay

リトライの最大間隔(ミリ秒)。
delay属性の値よりも小さい場合、「30000」が指定される。
デフォルト:0(0の場合、この設定は無視される)

multiplier

正の値の場合、次のリトライ間隔を算出するための乗数として使用する。
デフォルト:0(0の場合、この設定は無視される)

delayExpression

リトライ間隔を評価する式。
指数関数の場合は初期値、一様関数の場合は最小値として利用される。

maxDelayExpression

リトライの最大間隔を評価する式。
delay属性の値よりも小さい場合、「30000」が指定される。

multiplierExpression

リトライ間隔を算出するための乗数を評価する式。

random

リトライ間隔の決定方式が指数関数の場合に、リトライ間隔をランダムとする場合に「true」を設定する。

randomExpression

randomを値として評価する。

規定回数リトライしても例外発生する時の処理実装

規定回数リトライを実行しても、同じ例外がスローされ続けてしまった場合に、最終的に行う処理を定義する。
メソッドに「@Recoverアノテーションを付与して、メソッドのパラメータに対象の例外クラスを引数として受け取る。

import org.springframework.retry.annotation.Recover;

@Component
public class RetrySample {
  @Recover
  public void recover(OptimisticLockingFailureException e) {
    throw new RuntimeException("楽観排他例外が発生しました。", e);
  }
}