春のリトライガイド

春の再試行ガイド

1. 概要

Spring Retryは、失敗した操作を自動的に再起動する機能を提供します。 これは、エラーが一時的なものである場合(一時的なネットワーク障害など)に役立ちます。 Spring Retryは、プロセスの宣言的な制御と、拡張およびカスタマイズが容易なポリシーベースの動作を提供します。

この記事では、Spring Retryを使用してSpringアプリケーションに再試行ロジックを実装する方法を説明します。 また、追加のコールバックを受信するようにリスナーを構成します。

2. Mavenの依存関係

依存関係をpom.xmlに追加することから始めましょう。


    org.springframework.retry
    spring-retry
    1.1.5.RELEASE

Maven Centralspring-retryの最新バージョンを確認できます。

また、pom.xmlにSpring AOPを追加する必要があります。


    org.springframework
    spring-aspects

3. SpringRetryの有効化

アプリケーションでSpringRetryを有効にするには、@Configurationクラスに@EnableRetryアノテーションを追加する必要があります。

@Configuration
@EnableRetry
public class AppConfig { ... }

4. 注釈を付けて再試行する

アノテーションを使用することで、失敗時に再試行されるメソッド呼び出しを行うことができます。

4.1. @Retryable

メソッドに再試行機能を追加するには、@Retryableを使用できます。

@Service
public interface MyService {
    @Retryable(
      value = { SQLException.class },
      maxAttempts = 2,
      backoff = @Backoff(delay = 5000))
    void retryService(String sql) throws SQLException;
    ...
}

ここで、再試行動作は@Retryable.の属性を使用してカスタマイズされます。この例では、メソッドがSQLException.をスローした場合にのみ再試行が試行されます。最大2回の再試行と、5000ミリ秒の遅延があります。

@Retryableが属性なしで使用され、メソッドが例外で失敗した場合、1秒の遅延で最大3回再試行が試行されます。

4.2. @Recover

@Recoverアノテーションは、指定された例外で@Retryableメソッドが失敗した場合に、個別のリカバリーメソッドを定義するために使用されます。

@Service
public interface MyService {
    ...
    @Recover
    void recover(SQLException e, String sql);
}

したがって、retryService()メソッドがSQLExceptionをスローすると、recover()メソッドが呼び出されます。 適切な回復ハンドラーには、タイプThrowable(オプション). Sの最初のパラメーターがあります。 後続の引数は、失敗したメソッドの引数リストから、失敗したメソッドと同じ順序で、同じ戻り値の型で入力されます。

5. RetryTemplate

5.1 RetryOperations

Spring Retryは、execute()メソッドのセットを提供するRetryOperationsインターフェースを提供します。

public interface RetryOperations {
     T execute(RetryCallback retryCallback) throws Exception;

    ...
}

execute()のパラメータであるRetryCallbackは、障害時に再試行する必要があるビジネスロジックの挿入を可能にするインターフェイスです。

public interface RetryCallback {
    T doWithRetry(RetryContext context) throws Throwable;
}

5.2. RetryTemplate構成

RetryTemplateは、RetryOperationsの実装です。 @ConfigurationクラスでRetryTemplateBeanを構成しましょう。

@Configuration
public class AppConfig {
    //...
    @Bean
    public RetryTemplate retryTemplate() {
        RetryTemplate retryTemplate = new RetryTemplate();

        FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
        fixedBackOffPolicy.setBackOffPeriod(2000l);
        retryTemplate.setBackOffPolicy(fixedBackOffPolicy);

        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
        retryPolicy.setMaxAttempts(2);
        retryTemplate.setRetryPolicy(retryPolicy);

        return retryTemplate;
    }
}

RetryPolicyは、操作を再試行するタイミングを決定します。 SimpleRetryPolicyは、一定の回数再試行するために使用されます。

BackOffPolicyは、再試行間のバックオフを制御するために使用されます。 FixedBackOffPolicyは、続行する前に一定期間一時停止します。

5.3. RetryTemplateの使用

再試行処理を使用してコードを実行するには、retryTemplate.execute()を呼び出します。__

retryTemplate.execute(new RetryCallback() {
    @Override
    public Void doWithRetry(RetryContext arg0) {
        myService.templateRetryService();
        ...
    }
});

匿名クラスの代わりにラムダ式を使用して同じことを実現できます:__

retryTemplate.execute(arg0 -> {
    myService.templateRetryService();
    return null;
});

6. XML構成

Spring Retryは、Spring AOP名前空間を使用してXMLで構成できます。

6.1. XMLファイルの追加

クラスパスに、retryadvice.xmlを追加しましょう。

...

    
        
        
    

    
        
    

    
        
        
    

    
        
        
            
                
            
        
    

    
        
        
        
        
        
        
    

...

この例では、xmlRetryServiceメソッドのインターセプター内でカスタムRetryTemplateを使用しています。

6.2. XML設定の使用

classpathからretryadvice.xmlをインポートし、@AspectJのサポートを有効にします。

@Configuration
@EnableRetry
@EnableAspectJAutoProxy
@ImportResource("classpath:/retryadvice.xml")
public class AppConfig { ... }

7. リスナー

リスナーは、再試行時に追加のコールバックを提供します。 これらは、異なる再試行にわたるさまざまな横断的関心事に使用できます。

7.1. コールバックの追加

コールバックはRetryListenerインターフェースで提供されます。

public class DefaultListenerSupport extends RetryListenerSupport {
    @Override
    public  void close(RetryContext context,
      RetryCallback callback, Throwable throwable) {
        logger.info("onClose);
        ...
        super.close(context, callback, throwable);
    }

    @Override
    public  void onError(RetryContext context,
      RetryCallback callback, Throwable throwable) {
        logger.info("onError");
        ...
        super.onError(context, callback, throwable);
    }

    @Override
    public  boolean open(RetryContext context,
      RetryCallback callback) {
        logger.info("onOpen);
        ...
        return super.open(context, callback);
    }
}

openおよびcloseコールバックは、再試行全体の前後に発生し、onErrorは個々のRetryCallback呼び出しに適用されます。

7.2. リスナーの登録

次に、リスナー(DefaultListenerSupport)RetryTemplate Beanに登録します:

@Configuration
public class AppConfig {
    ...

    @Bean
    public RetryTemplate retryTemplate() {
        RetryTemplate retryTemplate = new RetryTemplate();
        ...
        retryTemplate.registerListener(new DefaultListenerSupport());
        return retryTemplate;
    }
}

8. 結果のテスト

結果を確認しましょう:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
  classes = AppConfig.class,
  loader = AnnotationConfigContextLoader.class)
public class SpringRetryTest {

    @Autowired
    private MyService myService;

    @Autowired
    private RetryTemplate retryTemplate;

    @Test(expected = RuntimeException.class)
    public void givenTemplateRetryService_whenCallWithException_thenRetry() {
        retryTemplate.execute(arg0 -> {
            myService.templateRetryService();
            return null;
        });
    }
}

テストケースを実行すると、以下のログテキストは、RetryTemplateとリスナーが正常に構成されたことを意味します。

2017-01-09 20:04:10 [main] INFO  o.b.s.DefaultListenerSupport - onOpen
2017-01-09 20:04:10 [main] INFO  o.example.springretry.MyServiceImpl
- throw RuntimeException in method templateRetryService()
2017-01-09 20:04:10 [main] INFO  o.b.s.DefaultListenerSupport - onError
2017-01-09 20:04:12 [main] INFO  o.example.springretry.MyServiceImpl
- throw RuntimeException in method templateRetryService()
2017-01-09 20:04:12 [main] INFO  o.b.s.DefaultListenerSupport - onError
2017-01-09 20:04:12 [main] INFO  o.b.s.DefaultListenerSupport - onClose

9. 結論

この記事では、Spring Retryを紹介しました。 アノテーションとRetryTemplateを使用した再試行の例を見てきました。 次に、リスナーを使用して追加のコールバックを構成しました。

この記事over on GitHubのソースコードを見つけることができます。