kagamihogeの日記

kagamihogeの日記です。

Spring Batch 4.1.x - Reference Documentation - Repeatのテキトー翻訳

https://docs.spring.io/spring-batch/4.1.x/reference/html/repeat.html#repeat

https://qiita.com/kagamihoge/items/12fbbc2eac5b8a5ac1e0 俺の訳一覧リスト

1. Repeat

1.1. RepeatTemplate

バッチ処理とは繰り返し処理であり、simple optimizationとなるかjobの一部となるか、のどちらかです。strategyパターン化・繰り返しの汎用化・iterator相当の機能、を提供するために、Spring BatchにはRepeatOperationsがあります。RepeatOperationsは以下の定義となります。

public interface RepeatOperations {

    RepeatStatus iterate(RepeatCallback callback) throws RepeatException;

}

引数のcallbackはインタフェースで以下の定義となっており、繰り返し処理のビジネスロジックを記述します。

public interface RepeatCallback {

    RepeatStatus doInIteration(RepeatContext context) throws Exception;

}

コールバックがイテレーションを終了するまで、コールバックを繰り返し実行します。上記インタフェースの戻り値はenumRepeatStatus.CONTINUABLERepeatStatus.FINISHEDのどちらかになります。RepeatStatus enumは呼び出し元に繰り返し処理を続行するかどうかを示します。基本的には、RepeatOperationsの実装はRepeatStatusをチェックしてイテレーションの終了判断の一つに使用します。コールバックでこれ以上の処理が無い事を呼び出し元に知らせるにはRepeatStatus.FINISHEDを返します。

RepeatOperationsの最もシンプルで汎用な実装はRepeatTemplateで、以下のように使います。

RepeatTemplate template = new RepeatTemplate();

template.setCompletionPolicy(new SimpleCompletionPolicy(2));

template.iterate(new RepeatCallback() {

    public RepeatStatus doInIteration(RepeatContext context) {
        // Do stuff in batch...
        return RepeatStatus.CONTINUABLE;
    }

});

上の例では、RepeatStatus.CONTINUABLEで、処理続行を示しています。また、コールバックは処理終了を呼び出し元に伝えるためにRepeatStatus.FINISHEDを返すことも出来ます。コールバック処理に内在する考慮事項によって、強制終了するイテレーションがありえます。上のsetCompletionPolicyのように終了条件を外部にデリゲートするコールバック以外は無限ループです。

1.1.1. RepeatContext

RepeatCallbackの引数はRepeatContextです。基本的にはコールバックで使うことは稀です。ただし、必要に応じて、イテレーション中の一時データを格納する場所として使えます。iterateが返ると、コンテキストは無くなります。

イテレーションがネストする場合、RepeatContextは親コンテキストを持ちます。親コンテキストは複数のiterate間でデータ共有したいときに便利です。たとえば、複数のサブシーケンス呼び出し後もイテレーションでのイベント発生数を保持し続けたい場合、などです。

1.1.2. RepeatStatus

Spring Batchで処理を終了するかどうかを指示するのにはRepeatStatusを使います。以下表のように、RepeatStatusには2種類の値があります。

Table 1. RepeatStatus Properties

Value Description
CONTINUABLE 未処理アイテムが存在
FINISHED ループ処理終了

また、RepeatStatusand()``でANDを取れます。これはcontinuableフラグとのANDです。つまり、両方ともCONTINUABLEでなければ、FINISHED```になります。

※以下コードは筆者補足

    System.out.println(RepeatStatus.CONTINUABLE.and(true));  //CONTINUABLE
    System.out.println(RepeatStatus.CONTINUABLE.and(false)); //FINISHED
    System.out.println(RepeatStatus.FINISHED.and(true));     //FINISHED
    System.out.println(RepeatStatus.FINISHED.and(false));    //FINISHED

1.2. Completion Policies

RepeatTemplateでは、iterateループの終了はCompletionPolicyが決定します。また、RepeatContextのファクトリも行います。RepeatTemplateRepeatContextの生成に設定されているポリシーを使用し、それをイテレーションRepeatCallbackに毎回渡します。コールバックがdoInIterationを完了すると、RepeatTemplateは状態(RepeatContextに保存)を更新するようCompletionPolicyを呼び出します。それから、イテレーションを完了するかどうかをポリシーで決定します。

Spring BatchはCompletionPolicyはシンプルで汎用の実装を用意しています。SimpleCompletionPolicyは固定回数まで実行します(RepeatStatus.FINISHEDで任意のタイミングで強制終了も可能)。

より複雑な終了判定を行う自前のポリシーを実装することも可能です。たとえば、オンラインシステムで使用中であればバッチジョブを起動しないようにするバッチ処理ウィンドウに対しては、カスタムのポリシーを作成します。

1.3. Exception Handling

RepeatCallback内で例外スローする場合、RepeatTemplateは例外再スローかどうかを判断するExceptionHandlerを参照します。

以下はExceptionHandlerの定義です。

public interface ExceptionHandler {

    void handleException(RepeatContext context, Throwable throwable)
        throws Throwable;

}

良くある使い方としては指定する例外スローの回数をカウントしてリミットに達したら失敗させます。Spring BatchはSimpleLimitExceptionHandlerと、これをもう少し柔軟にしたRethrowOnThresholdExceptionHandlerを用意しています。SimpleLimitExceptionHandlerはリミットのプロパティとチェック対象の例外の型を指定します。対象の例外の型のサブクラスはすべてカウント対象です。リミットに達するまでそれらの例外は無視し、達すると再スローします。それ以外の例外は常に再スローします。

SimpleLimitExceptionHandlerのオプションのプロパティuseParentは重要です。デフォルトではfalseで、リミットは現在のRepeatContextに対してのみ適用します。trueにすると、ネストしたイテレーションの兄弟コンテキスト間でリミットは保持されます。

1.4. Listeners

異なるイテレーションの横断的関心事を扱うコールバックがあると便利な場合があります。Spring BatchにはRepeatListenerがあります。RepeatTemplateRepeatListenerの実装を登録すると、イテレーション中にRepeatContextRepeatStatusのしかるべきポイントでコールバックが呼ばれます。

RepeatListenerは以下のような定義です。

public interface RepeatListener {
    void before(RepeatContext context);
    void after(RepeatContext context, RepeatStatus result);
    void open(RepeatContext context);
    void onError(RepeatContext context, Throwable e);
    void close(RepeatContext context);
}

opencloseイテレーション全体の開始前後のコールバックです。before, after, onErrorRepeatCallbackの呼び出しに適用されます。

なお、1つ以上のリスナーがある場合、そのリストで順序が発生します。この場合、openbeforeは同一順序で呼ばれ、after, onError, closeは逆順で呼ばれます。

1.5. Parallel Processing

RepeatOperationsの実装でコールバックをシーケンシャルに実行するという制限はありません。コールバックをパラレル実行する実装が可能な点は重要です。Spring BatchにはTaskExecutorRepeatTemplateがあり、RepeatCallbackの実行にSpringのTaskExecutorを使います。デフォルトではSynchronousTaskExecutorを使用し、これは同一スレッドでイテレーション全体を実行します(つまりRepeatTemplateと基本的に同じ)。

1.6. Declarative Iteration

ビジネスロジック実行をリピートしたい場合があります。これの古典的なサンプルはメッセージパイプラインの最適化です。もし頻繁にメッセージが到着する場合、メッセージごとに別々のトランザクションを張るよりも、メッセージをバッチ処理するのが効果的です。Spring BatchはRepeatOperationsにメソッド呼び出しをラップするAOPインターセプターを用意しています。RepeatOperationsInterceptorインターセプト対象メソッドを実行するとCompletionPolicyに従いRepeatTemplateで繰り返し実行します。

以下の例はjava configurationでprocessMessageのサービスメソッド呼び出しを繰り返し実行する設定です(AOPインターセプターの詳細な設定例はSpring User Guideを参照してください)。

@Bean
public MyService myService() {
        ProxyFactory factory = new ProxyFactory(RepeatOperations.class.getClassLoader());
        factory.setInterfaces(MyService.class);
        factory.setTarget(new MyService());

        MyService service = (MyService) factory.getProxy();
        JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
        pointcut.setPatterns(".*processMessage.*");

        RepeatOperationsInterceptor interceptor = new RepeatOperationsInterceptor();

        ((Advised) service).addAdvisor(new DefaultPointcutAdvisor(pointcut, interceptor));

        return service;
}

上のサンプルはインターセプターにデフォルトのRepeatTemplateを使用します。ポリシー・リスナー・などを変更するには、インターセプターに```RepeatTemplate````を設定してください。

インターセプトメソッドがvoidを返す場合、インターセプターは常にRepeatStatus.CONTINUABLEを返します(CompletionPolicyで何らかの終了条件を指定しない場合無限ループの危険性がある)。もしくは、インターセプトメソッドの戻り値がnullになるまでRepeatStatus.CONTINUABLEを返し、nullの時点でRepeatStatus.FINISHEDを返します。よって、ターゲットメソッドのビジネスロジックは、nullを返すかRepeatTemplateExceptionHandlerが再スローする例外のスローにより、処理終了を伝えることが出来ます。