Overview
ジョブの実行を管理する方法について説明する。
本機能は、チャンクモデルとタスクレットモデルとで同じ使い方になる。
ジョブの実行管理とは
ジョブの起動状態や実行結果を記録しバッチシステムを維持することを指す。
特に、異常発生時の検知や次に行うべき行動(異常終了後のリラン・リスタート等)を判断するために、必要な情報を確保することが重要である。
バッチアプリケーションの特性上、起動直後にその結果をユーザインターフェースで確認できることは稀である。
よって、ジョブスケジューラ/RDBMS/アプリケーションログといった、ジョブの実行とは別に実行状態・結果の記録を行う仕組みが必要となる。
Spring Batch が提供する機能
Spring Batchは、ジョブの実行管理向けに以下のインターフェースを提供している。
機能 | 対応するインターフェース |
---|---|
ジョブの実行状態・結果の記録 |
|
ジョブの終了コードとプロセス終了コードの変換 |
|
Spring Batch はジョブの起動状態・実行結果の記録にJobRepository
を使用する。
TERASOLUNA Batch 5.xでは、以下のすべてに該当する場合は永続化は任意としてよい。
-
同期型ジョブ実行のみでTERASOLUNA Batch 5.xを使用する。
-
ジョブの停止・リスタートを含め、ジョブの実行管理はすべてジョブスケジューラに委ねる。
-
Spring Batchがもつ
JobRepository
を前提としたリスタートを利用しない。
-
これらに該当する場合はJobRepository
が使用するRDBMSの選択肢として、インメモリ・組み込み型データベースであるH2
を利用する。
一方で非同期実行を利用する場合や、Spring Batchの停止・リスタートを活用する場合は、ジョブの実行状態・結果を永続化可能なRDBMSが必要となる。
デフォルトのトランザクション分離レベル
Spring Batchが提供するxsdでは、 |
インメモリJobRepositoryの選択肢
Spring Batch にはインメモリでジョブの実行管理を行う
|
ジョブスケジューラを使用したジョブの実行管理については各製品のマニュアルを参照のこと。
本ガイドラインではTERASOLUNA Batch 5.x内部でJobRepository
を用いたジョブの状態を管理するうえで関連する、
以下の項目について説明する。
-
-
状態を永続化する方法
-
状態を確認する方法
-
ジョブを手動停止する方法
-
How to use
JobRepository
はSpring Batchにより自動的にRDBMSの新規登録・更新が行われる。
ジョブの状態・実行結果の確認を行う場合は、意図しない変更処理がバッチアプリケーションの内外から行われることのないよう、以下のいずれかの方法を選択する。
-
ジョブの状態管理に関するテーブルに対しクエリを発行する
-
org.springframework.batch.core.explore.JobExplorer
を使用する
ジョブの状態管理
JobRepository
を用いたジョブの状態管理方法を説明する。
Spring Batchにより、以下のEntityがRDBMSのテーブルに登録される。
項番 | Entityクラス | テーブル名 | 生成単位 | 説明 |
---|---|---|---|---|
(1) |
|
|
1回のジョブ実行 |
ジョブの状態・実行結果を保持する。 |
(2) |
|
|
1回のジョブ実行 |
ジョブ内部のコンテキストを保持する。 |
(3) |
|
|
1回のジョブ実行 |
起動時に与えられたジョブパラメータを保持する。 |
(4) |
|
|
1回のステップ実行 |
ステップの状態・実行結果、コミット・ロールバック件数を保持する。 |
(5) |
|
|
1回のステップ実行 |
ステップ内部のコンテキストを保持する。 |
(6) |
|
|
ジョブ名とジョブパラメータの組み合わせ |
ジョブ名、およびジョブパラメータをシリアライズした文字列を保持する。 |
たとえば、1回のジョブ起動で3つのステップを実行した場合、以下の差が生じる
-
JobExecution
、JobExecutionContext
、JobExecutionParams
は1レコード登録される -
StepExecution
、StepExecutionContext
は3レコード登録される
また、JobInstance
は過去に起動した同名ジョブ・同一パラメータよる二重実行を抑止するために使用されるが、
TERASOLUNA Batch 5.xではこのチェックを行わない。詳細は二重起動防止を参照。
|
チャンク方式におけるStepExecutionの件数項目について
以下のように、不整合が発生しているように見えるが、仕様上妥当なケースがある。
|
状態の永続化
外部RDBMSを使用することでJobRepository
によるジョブの実行管理情報を永続化させることができる。
batch-application.propertiesの以下項目を外部RDBMS向けのデータソース、スキーマ設定となるよう修正する。
# (1)
# Admin DataSource settings.
admin.jdbc.driver=org.postgresql.Driver
admin.jdbc.url=jdbc:postgresql://serverhost:5432/admin
admin.jdbc.username=postgres
admin.jdbc.password=postgres
# (2)
spring-batch.schema.script=classpath:org/springframework/batch/core/schema-postgresql.sql
項番 | 説明 |
---|---|
(1) |
接頭辞 |
(2) |
アプリケーション起動時に |
管理用/業務用データソースの補足
|
ジョブの状態・実行結果の確認
JobRepository
からジョブの実行状態を確認する方法について説明する。
いずれの方法も、あらかじめ確認対象のジョブ実行IDが既知であること。
クエリを直接発行する
RDBMSコンソールを用い、JobRepository
が永続化されたテーブルに対して直接クエリを発行する。
admin=# select JOB_EXECUTION_ID, START_TIME, END_TIME, STATUS, EXIT_CODE from BATCH_JOB_EXECUTION where JOB_EXECUTION_ID = 1;
job_execution_id | start_time | end_time | status | exit_code
------------------+-------------------------+-------------------------+-----------+-----------
1 | 2017-02-14 17:57:38.486 | 2017-02-14 18:19:45.421 | COMPLETED | COMPLETED
(1 row)
admin=# select JOB_EXECUTION_ID, STEP_EXECUTION_ID, START_TIME, END_TIME, STATUS, EXIT_CODE from BATCH_STEP_EXECUTION where JOB_EXECUTION_ID = 1;
job_execution_id | step_execution_id | start_time | end_time | status | exit_code
------------------+-------------------+-------------------------+------------------------+-----------+-----------
1 | 1 | 2017-02-14 17:57:38.524 | 2017-02-14 18:19:45.41 | COMPLETED | COMPLETED
(1 row)
JobExplorer
を利用する
バッチアプリケーションと同じアプリケーションコンテキストを共有可能な環境下で、JobExplorer
をインジェクションすることでジョブの実行状態を確認する。
// omitted.
@Inject
private JobExplorer jobExplorer;
private void monitor(long jobExecutionId) {
// (1)
JobExecution jobExecution = jobExplorer.getJobExecution(jobExecutionId);
// (2)
String jobName = jobExecution.getJobInstance().getJobName();
Date jobStartTime = jobExecution.getStartTime();
Date jobEndTime = jobExecution.getEndTime();
BatchStatus jobBatchStatus = jobExecution.getStatus();
String jobExitCode = jobExecution.getExitStatus().getExitCode();
// omitted.
// (3)
jobExecution.getStepExecutions().forEach( s -> {
String stepName = s.getStepName();
Date stepStartTime = s.getStartTime();
Date stepEndTime = s.getEndTime();
BatchStatus stepStatus = s.getStatus();
String stepExitCode = s.getExitStatus().getExitCode();
// omitted.
});
}
項番 | 説明 |
---|---|
(1) |
インジェクションされた |
(2) |
|
(3) |
|
ジョブの停止
ジョブの停止とはJobRepository
の実行中ステータスを停止中ステータスに更新し、ステップの境界や
チャンク方式によるチャンクコミット時にジョブを停止させる機能である。
リスタートと組み合わせることで、停止された位置からの処理を再開させることができる。
リスタートの詳細はジョブのリスタートを参照。 |
「ジョブの停止」は仕掛かり中のジョブを直ちに中止する機能ではなく、 このため、ジョブの停止は「チャンクの切れ目など、節目となる処理が完了した際に停止するよう予約する」ことともいえる。 たとえば以下の状況下でジョブ停止を行っても、期待する動作とはならない。
|
以下、ジョブの停止方法を説明する。
-
コマンドラインからの停止
-
同期型ジョブ・非同期型ジョブのどちらでも利用できる
-
CommandLineJobRunner
の-stop
を利用する
-
$ java org.springframework.batch.core.launch.support.CommandLineJobRunner \
classpath:/META-INF/jobs/job01/job01.xml job01 -stop
-
ジョブ名指定によるジョブ停止は同名のジョブが並列で起動することが少ない同期バッチ実行時に適している。
$ java org.springframework.batch.core.launch.support.CommandLineJobRunner \
classpath:/META-INF/jobs/job01/job01.xml 3 -stop
-
ジョブ実行ID指定によるジョブ停止は同名のジョブが並列で起動することの多い非同期バッチ実行時に適している。
|
終了コードのカスタマイズ
同期実行によりジョブが終了した際、javaプロセスの終了コードをジョブの終了状態に応じてカスタマイズできる。 終了コードのカスタマイズには以下2つの作業が必要となる。
-
ジョブの終了状態を表す、ジョブの終了コードを変更する。
-
ジョブ・ステップの終了コード(文字列)と、プロセスの終了コード(数値)をマッピングする。
以下順に説明する。
ジョブの終了コードを変更する。
文字列として返却されるジョブの終了コードを変更できる。
-
ステップ終了時に任意の終了状態を返却するように
afterStep
メソッドを実装する。-
StepExecutionListener
を実装する。
-
@Component
public class ExitStatusChangeListener implements StepExecutionListener {
@Override
public ExitStatus afterStep(StepExecution stepExecution) {
ExitStatus exitStatus = stepExecution.getExitStatus();
if (conditionalCheck(stepExecution)) {
// (1)
exitStatus = new ExitStatus("CUSTOM STEP FAILED");
}
return exitStatus;
}
private boolean conditionalCheck(StepExecution stepExecution) {
// omitted.
}
}
<batch:step id="exitstatusjob.step">
<batch:tasklet transaction-manager="transactionManager">
<batch:chunk reader="reader" writer="writer" commit-interval="10" />
</batch:tasklet>
<batch:listeners>
<batch:listener ref="exitStatusChangeListener"/>
</batch:listeners>
</batch:step>
項番 | 説明 |
---|---|
(1) |
ステップの実行結果に応じて独自の終了コードを設定する。 |
-
ジョブ終了時にステップが返却した終了状態を最終的なジョブの終了状態として反映する
-
JobExecutionListener
の実装クラスで、afterJob
メソッドに実装を行う。
-
@Component
public class JobExitCodeChangeListener extends JobExecutionListenerSupport {
@Override
public void afterJob(JobExecution jobExecution) {
// (1)
if (jobExecution.getStepExecutions().stream()
.anyMatch(s -> "CUSTOM STEP FAILED".equals(s.getExitStatus().getExitCode()))) {
jobExecution.setExitStatus(new ExitStatus("CUSTOM FAILED"));
}
}
}
<batch:job id="exitstatusjob" job-repository="jobRepository">
<batch:step id="exitstatusjob.step">
<!-- omitted -->
</batch:step>
<batch:listeners>
<batch:listener ref="jobExitCodeChangeListener"/>
</batch:listeners>
</batch:job>
項番 | 説明 |
---|---|
(1) |
ジョブの実行結果に応じて、最終的なジョブの終了コードを |
終了コードのマッピングを追加定義する。
-
ジョブの終了状態と終了コードのマッピングを定義する。
<!-- exitCodeMapper -->
<bean id="exitCodeMapper"
class="org.springframework.batch.core.launch.support.SimpleJvmExitCodeMapper">
<property name="mapping">
<util:map id="exitCodeMapper" key-type="java.lang.String"
value-type="java.lang.Integer">
<!-- ExitStatus -->
<entry key="NOOP" value="0" />
<entry key="COMPLETED" value="0" />
<entry key="STOPPED" value="255" />
<entry key="FAILED" value="255" />
<entry key="UNKNOWN" value="255" />
<entry key="CUSTOM FAILED" value="100" /> <!-- Custom Exit Status -->
</util:map>
</property>
</bean>
プロセスの終了コードに1は厳禁
一般的にJavaプロセスはVMクラッシュやSIGKILLシグナル受信などによりプロセスが強制終了した際、 終了ステータスとして1を返却することがある。 正常・異常を問わずバッチアプリケーションの終了状態とは明確に区別すべきであるため、 アプリケーション内ではプロセスの終了コードとして1を定義しないこと。 |
終了ステータスと終了コードの違いについて
|
二重起動防止
Spring Batchではジョブを起動する際、JobRepositry
からJobInstance(BATCH_JOB_INSTANCEテーブル)
に対して
以下の組み合わせが存在するか確認する。
-
起動対象となるジョブ名
-
ジョブパラメータ
TERASOLUNA Batch 5.xではジョブ・ジョブパラメータの組み合わせが一致しても複数回起動可能としている。
つまり、二重起動を許容する。
詳細は、ジョブの起動パラメータを参照のこと。
二重起動を防止する場合は、ジョブスケジューラやアプリケーション内で実施する必要がある。
詳細な手段については、ジョブスケジューラ製品や業務要件に強く依存するため割愛する。
個々のジョブについて、二重起動を抑止する必要があるかについて、検討すること。
ロギング
ログの設定方法について説明する。
ログの出力、設定、考慮事項はTERASOLUNA Server 5.xと共通点が多い。まずは、 ロギングを参照のこと。
ここでは、TERASOLUNA Batch 5.x特有の考慮点について説明する。
ログ出力元の明確化
バッチ実行時のログは出力元のジョブやジョブ実行を明確に特定できるようにしておく必要がある。 そのため、スレッド名、ジョブ名、実行ジョブIDを出力するとよい。 特に非同期実行時は同名のジョブが異なるスレッドで並列に動作することになるため、 ジョブ名のみの記録はログ出力元を特定しにくくなる恐れがある。
それぞれの要素は、以下の要領で実現できる。
- スレッド名
-
logback.xml
の出力パターンである%thread
を指定する - ジョブ名・実行ジョブID
-
JobExecutionListener
を実装したコンポーネントを作成し、ジョブの開始・終了時に記録する
// package and import omitted.
@Component
public class JobExecutionLoggingListener implements JobExecutionListener {
private static final Logger logger =
LoggerFactory.getLogger(JobExecutionLoggingListener.class);
@Override
public void beforeJob(JobExecution jobExecution) {
// (1)
logger.info("job started. [JobName:{}][jobExecutionId:{}]",
jobExecution.getJobInstance().getJobName(), jobExecution.getId());
}
@Override
public void afterJob(JobExecution jobExecution) {
// (2)
logger.info("job finished.[JobName:{}][jobExecutionId:{}][ExitStatus:{}]"
, jobExecution.getJobInstance().getJobName(),
, jobExecution.getId(), jobExecution.getExitStatus().getExitCode());
}
}
<!-- omitted. -->
<batch:job id="loggingJob" job-repository="jobRepository">
<batch:step id="loggingJob.step01">
<batch:tasklet transaction-manager="jobTransactionManager">
<!-- omitted. -->
</batch:tasklet>
</batch:step>
<batch:listeners>
<!-- (3) -->
<batch:listener ref="jobExecutionLoggingListener"/>
</batch:listeners>
</batch:job>
<!-- omitted. -->
項番 | 説明 |
---|---|
(1) |
ジョブの開始前にジョブ名とジョブ実行IDをINFOログに出力している。 |
(2) |
ジョブの終了時は(1)に加えて終了コードも出力している。 |
(3) |
コンポーネントとして登録されている |
ログ監視
バッチアプリケーションは運用時のユーザインターフェースはログが主体となる。 監視対象と発生時のアクションを明確に設計しておかないと、 フィルタリングが困難となり、対処に必要なログが埋もれてしまう危険がある。 このため、ログの監視対象としてキーワードとなるメッセージやコード体系をあらかじめ決めておくとよい。 ログに出力するメッセージ管理については、後述のメッセージ管理を参照。
ログ出力先
バッチアプリケーションにおけるログの出力先について、どの単位でログを分散/集約するのかを設計するとよい。 たとえばフラットファイルにログを出力する場合でも以下のように複数パターンが考えられる。
-
1ジョブあたり1ファイルに出力する
-
複数ジョブを1グループにまとめた単位で1ファイルに出力する
-
1サーバあたり1ファイルに出力する
-
複数サーバをまとめて1ファイルに出力する
いずれも対象システムにおける、ジョブ総数/ログ総量/発生するI/Oレートなどによって、 どの単位でまとめるのが最適かが分かれる。 また、ログを確認する方法にも依存する。ジョブスケジューラ上から参照することが多いか、コンソールから参照することが多いか、 といった活用方法によっても選択肢が変わると想定する。
重要なことは、運用設計にてログ出力を十分検討し、試験にてログの有用性を確認することに尽きる。
メッセージ管理
メッセージ管理について説明する。
コード体系のばらつき防止や、監視対象のキーワードとしての抽出を設計しやすくするため、 一定のルールに従ってメッセージを付与することが望ましい。
なお、ログと同様、メッセージ管理についても基本的にはTERASOLUNA Server 5.xと同様である。
MessageSourceの活用について
プロパティファイルからメッセージを使用するには
launch-context.xml
|
Appendix. Spring Batch Admin
Spring Batch AdminはSpring Batchのサブプロジェクトであり、Webインターフェースによってジョブの実行状態を確認することができる。 テスト/商用環境によらず手軽に参照できるため紹介する。
Spring Batch Adminはサンプルアプリケーションの形で配布されている。 ここではWebコンテナとしてApache Tomcatを用い、warファイルをデプロイする。
Spring Batch Adminはジョブの実行状態・結果の確認だけでなく、ジョブの起動・停止も可能である。 その場合は同様のwarファイルにジョブも同梱する必要があり、Webコンテナでジョブを実行することが必須という強い制約が生まれる。 実行状態・結果の確認だけならばその必要性はないため、ここではあくまで参照方法として紹介する。 |
インストール手順は以下のとおり。
-
リリース配布サイトより、 1.3.1.RELEASEのzipをダウンロードし、任意の場所で展開する。
-
外部RDBMS定義のプロパティファイル
batch-RDBMSNAME.properties
を作成する。-
spring-batch-admin-1.3.1.RELEASE/spring-batch-admin-sample/src/main/resources
に配置する。
-
# Placeholders batch.*
# for PostgreSQL:
# (1)
batch.jdbc.driver=org.postgresql.Driver
batch.jdbc.url=jdbc:postgresql://localhost:5432/admin
batch.jdbc.user=postgres
batch.jdbc.password=postgres
batch.jdbc.testWhileIdle=true
batch.jdbc.validationQuery=SELECT 1
# (2)
batch.schema.script=classpath:/org/springframework/batch/core/schema-postgresql.sql
batch.drop.script=classpath*:/org/springframework/batch/core/schema-drop-postgresql.sql
batch.business.schema.script=classpath:/business-schema-postgresql.sql
batch.database.incrementer.class=org.springframework.jdbc.support.incrementer.PostgreSQLSequenceMaxValueIncrementer
# Non-platform dependent settings that you might like to change
# (3)
batch.data.source.init=false
項番 | 説明 |
---|---|
(1) |
接続先RDBMSのJDBCドライバ設定を記述する。 |
(2) |
|
(3) |
Spring Batch Admin起動時に |
-
spring-batch-admin-1.3.1.RELEASE/spring-batch-admin-sample/
配下のpom.xmlに、 JDBCドライバの依存ライブラリを追加する。
<project>
<!-- omitted. -->
<dependencies>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4.1212.jre7</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<!-- omitted. -->
</project>
-
mvn clean package
コマンドによりwarファイルを作成する。 -
環境変数
JAVA_OPTS
に外部RDBMS名-DENVIRONMENT=postgresql
を設定し、Tomcatを起動する。
$ export JAVA_OPTS="$JAVA_OPTS -DENVIRONMENT=postgresql"
$ echo $JAVA_OPTS
-DENVIRONMENT=postgresql
$ TOMCAT_HOME/bin/catalina.sh run
-
target/spring-batch-admin-1.3.1.war
をTomcatにデプロイする。 -
ブラウザで
http://tomcathost:port/spring-batch-admin-sample-1.3.1.RELEASE/
を開き、Jobsを選択する。
-
実行状態・実行結果取得対象のジョブ名を選択する。
-
対象ジョブの実行状態・結果が表示される。