Spring Batch で CommandLineRunner を使った CLI 実行時に任意の終了コードを返す

Java
JavaSpringバックエンド

この記事では、Spring Batch を CLI で実行した際に任意の終了コードを返す方法を解説します。

CLI で実行するには CommandLineRunner を利用してますが、この基本的な実行方法については以下の記事を参照ください。

Spring Batch を利用する際は、shell 等を利用してコマンドライン経由で実行するケースは多いかと思います。そのとき、デフォルトの 0, 1, 2 ではなく、バッチアプリケーション固有の数値を返したい場合はあると思います。また、返却コードのパターンもより多く必要になることも考えられます。

CommandLineJobRunner の場合のやり方だったり、xml ベースでのやり方は記事があったのですが、CommandLineRunner かつ java で完結する記事は少ない(というか見つけられませんでした)。
歴史が長いことは良いことですが、歴史が長いゆえに一般的な方法が探しづらいですね。

コードは前回の続きにしています。

対応方法

やることは以下です。

  1. 終了コードの定義
  2. 処理終了後に終了コードを設定
  3. 終了コードを返却する

終了コードの定義(SimpleJvmExitCodeMapper)

エラーコードは SimpleJvmExitCodeMapper を継承することでカスタマイズ可能です。

SimpleJvmExitCodeMapper クラス自体にもコンストラクタで定義はされていますが、継承した場合は終了コードの全パターンを再定義する必要があります。以下は、元々用意されている定義に対して、別の終了コードを指定しつつ、カスタムの ExitStatus を定義したものです。

@Component
public class MyBatchExitCodeMapper extends SimpleJvmExitCodeMapper {
    Map<String, Integer> mapping = new HashMap<String, Integer>();

    private MyBatchExitCodeMapper () {
        mapping.put(ExitStatus.COMPLETED.getExitCode(), Integer.valueOf(100));
        mapping.put(ExitStatus.EXECUTING.getExitCode(), Integer.valueOf(101));
        mapping.put(ExitStatus.FAILED.getExitCode(), Integer.valueOf(102));
        mapping.put(ExitStatus.NOOP.getExitCode(), Integer.valueOf(103));
        mapping.put(ExitStatus.STOPPED.getExitCode(), Integer.valueOf(104));
        mapping.put(ExitStatus.UNKNOWN.getExitCode(), Integer.valueOf(105));
        mapping.put("CUSTOM_STATUS", Integer.valueOf(255));
        setMapping(mapping);
    }
    @Override
    public int intValue(String exitCode) {
        return mapping.get(exitCode);
    }
}

終了コードの設定(ExitCodeGenerator)

終了コードを定義しても、それをアプリケーションの戻り値として設定しないといけません。

SpringApplication の戻り値は ExitCodeGenerator を利用することで指定が可能です。getExitCode を実装し、run の中で設定します。ここではジョブ実行結果の戻り値に対応するコードを終了コードとしています。

public class MyBatchCommandLineRunner  implements CommandLineRunner, ExitCodeGenerator {
...
    private int exitCode;

    @Override
    public int getExitCode() {
        return exitCode;
    }
...
    @Override
    public void run(String... args) throws Exception {
   ...
        // exitCodeMapper.intValue で定義した戻り値の map から対応する終了コードを取得します
        int returnValue = exitCodeMapper.intValue(jobExecution.getExitStatus().getExitCode());

        // 終了コードを設定
        this.exitCode = returnValue;
    }
}

終了コードを返却する

Java プロセスとしての終了コードは System.exit メソッドで指定できます。
そこに、SpringApplication の実行の戻り値(上で設定した exitCode )を指定します。

@SpringBootApplication
public class SpringBatchCliApplication {

	public static void main(String[] args) {
		SpringApplication app = new SpringApplication(SpringBatchCliApplication.class);
		int exitCode = SpringApplication.exit(app.run(args));
		System.out.println("exit status: " + exitCode);
		System.exit(exitCode);
	}
}

実行

実際に期待した結果になるかの確認です。

Tasklet でカスタムステータスを指定する

Tasklet でステップの ExitStatusCUSTOM_STATUS に指定します。

@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext context) {
    ...
    contribution.setExitStatus(new ExitStatus("CUSTOM_STATUS"));
    ....
}

結果は以下の通り。255 になってますね。

実行結果 - Tasklet でカスタムステータスを指定する
実行結果 – Tasklet でカスタムステータスを指定する

試しに、今度は new ExitStatus("CUSTOM_STATUS") の部分を、ExitStatus.FAILED にすると、ちゃんと 102 になります。

実行結果 - Tasklet でカスタムステータスを指定する2
実行結果 – Tasklet でカスタムステータスを指定する2

ステップ の結果によって ジョブの ExitStatus を変える

今度は Tasklet でステップの ExitStatus を指定した後、その結果によってジョブの ExitStatus を変えてみます。変更は JobExecutinListenerSupportafterJob で行います。

以下では、ステップの実行結果に FAILED があると、ジョブの結果を CUSTOM_STATUS にしています。

public class BatchJobListener extends JobExecutionListenerSupport {
    ....

    @Override
    public void afterJob(JobExecution jobExecution) {
        System.out.println("aftefJob");
        for (StepExecution stepExecution : jobExecution.getStepExecutions()) {
            if (stepExecution.getExitStatus().getExitCode().equals("FAILED")) {
                jobExecution.setExitStatus(new ExitStatus("CUSTOM_STATUS"));
                return;
            }
        }
    }
}

結果だけ見ても代わり映えしませんが、ちゃんと 255 が返ってきています。

実行結果 - ステップ の結果によって ジョブの ExitStatus を変える
実行結果 – ステップ の結果によって ジョブの ExitStatus を変える

まとめ

分かってしまえば、数行で終了コードが指定でき、カスタマイズも自由にできました。
また、ステップの実行結果によっても柔軟に終了コードが設定できそうです。

コメント