LoginSignup
1
1

springでリトライ処理を実装してみる

Posted at

今回も備忘録です。

このドキュメントについて

下記について記載していきます。
@Retryableを利用したリトライ処理の実装
・RetryTemplateを利用したリトライ処理の実装

実行環境

・Java17
・springboot 3.0.2

実装

@Retryableを利用したリトライ処理の実装

@Retryable(retryFor= Exception.class, maxAttempts = 5, backoff = @Backoff(delay = 1000))
public ResponseEntity<String> retryTest() {
    count = count + 1;
    log.info("試行回数:" + count + "、時間:" + LocalDateTime.now());
    throw new RuntimeException("処理失敗してます");
}

@Recover
public ResponseEntity<String> recover(Exception e) {
    log.info(e.getMessage());
    return ResponseEntity.ok("リトライ後のリカバリー");
}

説明:

  1. リトライしたいメソッドに@Retryableを付与することで、リトライが可能になる
    引数部分に詳しい設定を行う。
    ・retryFor:リトライ対象のExceptionを設定
    ・maxAttempts:最大のリトライ回数を設定
     (初回実行時も含めるので、上記例だと4回リトライすることになる)
    ・backoff:リトライ間隔の時間を設定できる
     (上記例だと1秒。multiplierというのもあり、リトライする度に間隔を伸ばすことができる。)
      
    2.@Recoverをメソッドに付与すると、リトライしてもダメだった場合のリカバリーができる

RetryTemplateを利用したリトライ処理の実装

複数箇所で同様のリトライ処理を入れたい場合は、こちらを利用するのがおすすめ。

@Bean(name = "normalTemplate")
public RetryTemplate normalTemplate() {
  return RetryTemplate.
            builder()
            .maxAttempts(5)
            .fixedBackoff(3000)
            .retryOn(RuntimeException.class)
            .build();
}

説明:

  1. リトライの設定に複雑さを求めないのであれば、RetryTemplateのbuilderでさくっと設定ができる。
  2. maxAttempts:最大リトライ回数
    fixedBackoff:リトライ間隔
    retryOn:リトライ対象のException
    3.@BeanでDIコンテナに登録して、利用したいクラスで依存性注入してあげればどこでも利用できる

もう少し複雑な設定もできる。
@Configuration
public class RetryConfig {

    @Bean
    public SimpleRetryPolicy simpleRetryPolicy() {
        var simpleRetryPolicy = new SimpleRetryPolicy();
        simpleRetryPolicy.setMaxAttempts(5);
        return simpleRetryPolicy;
    }

    @Bean
    public FixedBackOffPolicy fixedBackOffPolicy() {
        var fixedBackOffPolicy = new FixedBackOffPolicy();
        fixedBackOffPolicy.setBackOffPeriod(3000);
        return fixedBackOffPolicy;
    }

    @Bean
    public ExceptionClassifierRetryPolicy exceptionClassifierRetryPolicy(SimpleRetryPolicy simpleRetryPolicy) {
        var exceptionClassifierRetryPolicy = new ExceptionClassifierRetryPolicy();
        exceptionClassifierRetryPolicy.setExceptionClassifier(set -> {
            return set instanceof RuntimeException ? simpleRetryPolicy : new NeverRetryPolicy();
        });

        return exceptionClassifierRetryPolicy;
    }

    @Bean(name = "customTemplate")
    public RetryTemplate retryTemplate(ExceptionClassifierRetryPolicy exceptionClassifierRetryPolicy, FixedBackOffPolicy fixedBackOffPolicy) {
        var retryListener = new RetryListener() {
            @Override
            public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback,
                                                  Throwable throwable) {
                if (context.getRetryCount() ==3) {
                    throw new ExampleException("retryListerからのエラー出力", 500);
                }
            }
        };

        return RetryTemplate
                .builder()
                .customPolicy(exceptionClassifierRetryPolicy)
                .customBackoff(fixedBackOffPolicy)
                .withListener(retryListener)
                .build();
    }

}

説明:
1.SimpleRetryPolicyやFixedBackOffPolicyを汎用的に利用できるように@Beanで登録しておく。

2.ExceptionClassifierRetryPolicyでExceptionごとにretryPolicyを設定する。
例で言うと、RuntimeExceptionならSimpleRetryPolicyで、それ以外ならリトライしないNeverRetryPolicyを設定する。

3.RetryListenerはエラーが起こった時や、成功した時に処理を入れ込むことができる
上記だと、リトライカウントが3回目の時はExampleExceptionを投げる設定になっている

4.あとはRetryTemplateのbuilderで設定してあげれば終わり

まとめ

他システムとの通信時やできる限り失敗したくない処理の時には、必ず役に立つspringのRetry処理になるので知っておいて損はないです。

もっといい書き方とかあれば教えてほしいです。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1