Spring Boot Batchの実行とメタデータテーブル
目次
背景
必要に迫られSrping Boot Batch
の勉強をはじめました。今回は、起動方法と自動で作成されるメタデータテーブルの確認を行います。
ハンズオン
早速ですが動くものを作ります。
事前準備
プロジェクトの作成
spring initializrで以下の通りプロジェクトを作成します。
DBの用意
こちらの記事を元に、PostgreSQLの用意を行います。
コーディング
上記で作成したプロジェクトを元に以下の通りコーディングを行います。
Tasklet
Spring Batch
では、タスクレットとチャンクという2つのモデルが存在します。今回は前者を採用します。また、今回は実行時にコマンドライン引数を渡す為、受け取れる様にしておきます。
@Component @Scope("step") // (1) public class HelloTasklet implements Tasklet { @Value("#{jobParameters[name] ?: \"Nanashi\"}") // (2) private String name; @Override public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception { System.out.println("Hello: " + name); return RepeatStatus.FINISHED; // (3) } }
JobParameters
から値を受け取るに当たり、@Scope("step")
を付与する必要があります。詳しくは、こちらを参照ください。JobParameters
から、パラメータ名name
の値を取得します。引数が無い場合、デフォルト値として"Nanashi"が設定されます。- 戻り値に指定可能な値は、
RepeatStatus.CONTINUABLE
(処理継続)とRepeatStatus.FINISHED
(処理終了)の2値になります。今回は、終了するので後者を選択します。
JavaConfig
@Configuration // (1) @EnableBatchProcessing // (2) @AllArgsConstructor public class BatchConfig { private final JobBuilderFactory jobBuilderFactory; private final StepBuilderFactory stepBuilderFactory; private final HelloTasklet helloTasklet; @Bean public Step helloStep() { // (3) return stepBuilderFactory.get("helloStep").tasklet(helloTasklet).build(); } } @Bean public Job helloJob(Step helloStep) { // (4) return jobBuilderFactory.get("helloJob").flow(helloStep).end().build(); }
- Java上で設定を行う為に、
@Configuration
を付与します。 - Spring Batchで必要になるBean定義を自動で行う為に、
@EnableBatchProcessing
を付与します。 - ステップの定義を行う。
- 上記で定義したステップを保持するジョブを定義する。ジョブとステップの関係はこちらを参照ください。
エントリポイント
@SpringBootApplication public class SpringBootBatchSample01Application { public static void main(String[] args) { SpringApplication.run(SpringBootBatchSample01Application.class, args); } }
設定ファイル
src/main/resources
にapplication.yml
を作成し、以下の通り記載します。元々存在したapplication.properties
は削除します。
spring: datasource: url: jdbc:postgresql://localhost:5432/postgres driver-class-name: org.postgresql.Driver username: postgres password: password batch: initialize-schema: always # DBを初期化する為の設定
実行
1回目
実行前のDB
まず、アプリケーションを実行する前にDBの状態を確認しましょう。コンテナ上のDBにログインし*1、以下コマンドを発行します。結果、以下の通りテーブルが1つも存在しないことが確認できます。
postgres=# \dt Did not find any relations.
アプリケーションの実行
次に、プロジェクトのルートディレクトリでmvn spring-boot:run
を発行します。結果、以下の通りデフォルト値のNanashiが出力されました。
... 2020-08-01 13:56:44.433 INFO 14659 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [helloWorldStep] Hello: Nanashi 2020-08-01 13:56:44.476 INFO 14659 --- [ main] o.s.batch.core.step.AbstractStep : Step: [helloWorldStep] executed in 43ms ...
実行後のDB
アプリケーション実行後のDBの状態を再度確認してみましょう。結果、以下の通り6つのテーブルが作成されています。各テーブルの説明に関して、こちらとこちらをご覧ください。
postgres=# \dt List of relations Schema | Name | Type | Owner --------+------------------------------+-------+---------- public | batch_job_execution | table | postgres public | batch_job_execution_context | table | postgres public | batch_job_execution_params | table | postgres public | batch_job_instance | table | postgres public | batch_step_execution | table | postgres public | batch_step_execution_context | table | postgres (6 rows)
batch_job_instance
テーブルとbatch_job_execution
テーブルの中身を確認してみましょう。以下の通り実行が記録されています。
postgres=# select * from batch_job_instance; job_instance_id | version | job_name | job_key -----------------+---------+---------------+---------------------------------- 1 | 0 | helloWorldJob | d41d8cd98f00b204e9800998ecf8427e (1 row) postgres=# select * from batch_job_execution; job_execution_id | version | job_instance_id | create_time | start_time | end_time | status | exit_code | exit_message | last_updated | job_configuration_location ------------------+---------+-----------------+-------------------------+-------------------------+-------------------------+-----------+-----------+--------------+-------------------------+---------------------------- 1 | 2 | 1 | 2020-07-30 08:36:10.414 | 2020-07-30 08:36:10.445 | 2020-07-30 08:36:10.538 | COMPLETED | COMPLETED | | 2020-07-30 08:36:10.538 | (1 row)
2回目
アプリケーションの実行
再度、mvn spring-boot:run
を発行し、アプリケーションを実行してみましょう。結果、以下ログが出力されジョブが起動しませんでした。
2020-07-31 08:02:03.801 INFO 12339 --- [ main] o.s.batch.core.job.SimpleStepHandler : Step already complete or not restartable, so no action to execute: StepExecution: id=1, version=3, name=helloWorldStep, status=COMPLETED, exitStatus=COMPLETED, readCount=0, filterCount=0, writeCount=0 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=1, rollbackCount=0, exitDescription=
調査したところ、JobInstance
はジョブ名とジョブパラメータ毎に生成され、引数なしの再実行は1回目と同様のJobInstance
と見なされた様です。そして、1回目はすでにステータスがCOMPLETED
になっている為、該当のログが出力されました。
そこで、mvn spring-boot:run -Dspring-boot.run.arguments="name=Yamada"
と、コマンドライン引数を与えて実行したことろ、以下の通り無事実行することができました。
... 2020-08-01 17:36:21.093 INFO 14877 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [helloWorldStep] Hello: Yamada 2020-08-01 17:36:21.134 INFO 14877 --- [ main] o.s.batch.core.step.AbstractStep : Step: [helloWorldStep] executed in 40ms ...
実行後のDB
再度、batch_job_instanceテーブルとbatch_job_executionテーブルの中身を確認してみましょう。結果、以下の通り2回分の実行が記録されています。
postgres=# select * from batch_job_instance; job_instance_id | version | job_name | job_key -----------------+---------+---------------+---------------------------------- 1 | 0 | helloWorldJob | d41d8cd98f00b204e9800998ecf8427e 2 | 0 | helloWorldJob | e44a461448a1f43e3c7fcd84c6f17fe3 (2 rows) postgres=# select * from batch_step_execution; step_execution_id | version | step_name | job_execution_id | start_time | end_time | status | commit_count | read_count | filter_count | write_count | read_skip_count | write_skip_count | process_skip_count | rollback_count | exit_code | exit_message | last_updated -------------------+---------+----------------+------------------+-------------------------+-------------------------+-----------+--------------+------------+--------------+-------------+-----------------+------------------+--------------------+----------------+-----------+--------------+------------------------- 1 | 3 | helloWorldStep | 1 | 2020-07-30 08:36:10.486 | 2020-07-30 08:36:10.528 | COMPLETED | 1 | 0 | 0 | 0 | 0 | 0 |0 | 0 | COMPLETED | | 2020-07-30 08:36:10.528 2 | 3 | helloWorldStep | 3 | 2020-07-31 08:03:39.362 | 2020-07-31 08:03:39.407 | COMPLETED | 1 | 0 | 0 | 0 | 0 | 0 |0 | 0 | COMPLETED | | 2020-07-31 08:03:39.407 (2 rows)
*1:https://fujiu.hatenablog.com/entry/2020/06/09/201255を合わせてご参照ください。