背景
JOBスケジューラー(オンプレ)から RESTAPI (SpringBoot) 経由でバッチを起動している。
オンプレからAWSへの移行に伴い、JOBスケジューラー(オンプレ)から Amazon EventBridge Scheduler へ移行したい。
負荷分散のため、バッチの起動は RESTAPI から ECS タスクによる起動(SpringBatch)に変更する。
課題
EventBridge には 以下の仕様が存在します。
まれに、単一のイベントまたはスケジュールされた期間に対して同じルールが複数回実行されたり、トリガーされる特定のルールに対して同じターゲットを複数回呼び出されたりする場合があります。
つまり、EventBridge Rules/Scheduler は ECS タスクを稀に重複実行します。😨
Scheduler には重複実行の確率を下げる仕組み ( フレックスタイムウィンドウ ) が存在しますが、0 % にはならないようなのでアプリケーション側で対処する必要があります。
対処内容
eventbridge 重複起動
でググるといろいろな方法が出てきますが、SpringBatch の仕組みで対処しました。
SpringBatch の RunIdIncrementer は JOBを実行する度に run.id というJOBパラメータを +1 するので、何回も同じJOBを動かすことができます。
しかし、何回も同じJOBを動かせてしまうと EventBridge の重複実行は防げません。
そこで、以下のような MonthlyIncrementer を作りました。これを RunIdIncrementer の代わりに設定します。
public class MonthlyIncrementer implements JobParametersIncrementer {
@Override
public JobParameters getNext(@Nullable JobParameters previousParameters) {
JobParameters jobParameters = Optional.ofNullable(previousParameters).orElse(new JobParameters());
YearMonth now = YearMonth.from(LocalDateTime.now());
return new JobParametersBuilder(jobParameters)
.addString("run.monthly.id", now.toString())
.toJobParameters();
}
}
これにより、月をまたがない限り JOB パラメータが変わらなくなり重複実行を防ぐことができます。
日次バッチの場合もほぼ同様です。