Spring BatchでメタデータによるJobの再実行

概要

Spring Batchではデータベースに処理結果をメタデータとして記録することができます。
このメタデータにはバッチ処理が正常に終了したかどうかが記録されているので失敗したバッチ処理の再実行に利用することができます。

この仕組みをうまく利用するためにバッチ処理でエラーが発生したときはすみやかに例外を発生して終了するようにします。

メタデータの構成

メタデータは次の6個のテーブルにより構成されています。

0002_メタデータ

  • BATCH_JOB_INSTANCE
    バッチ処理の本体であるJobを格納するテーブル
  • BATCH_JOB_EXECUTION
    Jobの実行を記録するテーブル、処理が成功したか失敗したかを記録する。

  • BATCH_STEP_EXECUTION
    Jobに含まれるStepの実行を記録するテーブル、処理が成功したかどうかを記録する。

Jobの一覧

メタデータからバッチ処理の状況を取得することができます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
select
    x.JOB_EXECUTION_ID JOB_EXECUTION_ID,
    x.VERSION VERSION,
    x.JOB_INSTANCE_ID JOB_INSTANCE_ID,
    x.CREATE_TIME CREATE_TIME,
    x.START_TIME START_TIME,
    x.END_TIME END_TIME,
    x.STATUS STATUS,
    x.EXIT_CODE EXIT_CODE,
    x.EXIT_MESSAGE EXIT_MESSAGE,
    x.LAST_UPDATED LAST_UPDATED,
    x.JOB_CONFIGURATION_LOCATION JOB_CONFIGURATION_LOCATION
  from
    BATCH_JOB_EXECUTION x
      inner join
        BATCH_JOB_INSTANCE n
      on
        x.JOB_INSTANCE_ID=n.JOB_INSTANCE_ID
  order by
    x.START_TIME, x.JOB_INSTANCE_ID, x.JOB_EXECUTION_ID

メタデータを利用した再実行

BATCH_JOB_EXECUTIONの処理結果から失敗したJobを取得して再実行を行うことができます。

Spring BatchJobの実行終了時にプログラムを終了します。
連続してJobを実行するためにJob終了時の処理を変更します。

  • CommandLineRunnerを継承したJob実行クラスより抜粋
    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Override
    public void run(String... args) throws Exception {
      CommandLineJobRunner.presetSystemExiter(
          new SystemExiter() {
            public void exit(int status) {
              logger.trace("SystemExiter:status=" + status);
            }
          }
      );

メタデータから失敗したJobを取得して再実行を指示します。
再実行はCommandLineJobRunnerに渡す引数で指定します。

  • 失敗したJobを取得するSQL
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    select
        x.JOB_EXECUTION_ID JOB_EXECUTION_ID,
        x.VERSION VERSION,
        x.JOB_INSTANCE_ID JOB_INSTANCE_ID,
        x.CREATE_TIME CREATE_TIME,
        x.START_TIME START_TIME,
        x.END_TIME END_TIME,
        x.STATUS STATUS,
        x.EXIT_CODE EXIT_CODE,
        x.EXIT_MESSAGE EXIT_MESSAGE,
        x.LAST_UPDATED LAST_UPDATED,
        x.JOB_CONFIGURATION_LOCATION JOB_CONFIGURATION_LOCATION
      from
        BATCH_JOB_EXECUTION x
          inner join
            BATCH_JOB_INSTANCE n
          on
            x.JOB_INSTANCE_ID=n.JOB_INSTANCE_ID
      where
        n.JOB_NAME='billingBatchJob' and
        x.EXIT_CODE != 'COMPLETED'
  • 失敗したJobのインスタンスから成功したJobを検索するSQL

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    select
        JOB_EXECUTION_ID,
        VERSION,
        JOB_INSTANCE_ID,
        CREATE_TIME,
        START_TIME,
        END_TIME,
        STATUS,
        EXIT_CODE,
        EXIT_MESSAGE,
        LAST_UPDATED,
        JOB_CONFIGURATION_LOCATION
      from
        BATCH_JOB_EXECUTION
      where
        JOB_INSTANCE_ID = @jobInstanceId and
        EXIT_CODE = 'COMPLETED'

検索したJobのインスタンスに成功したJobが見つからなかったときはJobの再実行を行います。
Jobの再実行を行うときはコマンドの引数として”-restart”を指定します。

  • jobExecutionIdを指定してJobの再実行
    1
    2
    3
    4
    CommandLineJobRunner.main(new String[] {
        "com.sios.azure.billing.cost.batch.BatchConfiguration",
        jobExecutionId,
        "-restart"});

メタデータの削除

Jobの再実行を行うと条件によって必ず失敗するJobが残ってしまうことがあります。
その際にはそのJobをメタデータから削除する必要があります。

次のSQLにより特定のJobインスタンスを削除することができます。
@instance_idの記述はMySQLに合わせています。
使用しているデータベースに合わせる必要があります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
set @instance_id=1234;
 
delete from BATCH_STEP_EXECUTION_CONTEXT where STEP_EXECUTION_ID in
  (select STEP_EXECUTION_ID from BATCH_STEP_EXECUTION where JOB_EXECUTION_ID  in
    (select JOB_EXECUTION_ID from BATCH_JOB_EXECUTION where JOB_INSTANCE_ID=@instance_id));
 
delete from BATCH_STEP_EXECUTION where JOB_EXECUTION_ID in
  (select JOB_EXECUTION_ID from BATCH_JOB_EXECUTION where JOB_INSTANCE_ID=@instance_id);
 
delete from BATCH_JOB_EXECUTION_CONTEXT where JOB_EXECUTION_ID in
  (select JOB_EXECUTION_ID from BATCH_JOB_EXECUTION where JOB_INSTANCE_ID=@instance_id);
 
delete from BATCH_JOB_EXECUTION_PARAMS where JOB_EXECUTION_ID in
  (select JOB_EXECUTION_ID from BATCH_JOB_EXECUTION where JOB_INSTANCE_ID=@instance_id);
 
delete from BATCH_JOB_EXECUTION where JOB_INSTANCE_ID=@instance_id;
 
delete from BATCH_JOB_INSTANCE where JOB_INSTANCE_ID=@instance_id;
ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です