バッチと定期ジョブ — 途中で落ちたとき、もう一度流して大丈夫か
夜間の請求バッチが 3,200 件目で止まった。朝、担当者が最初から流し直した。最初の 3,200 人に、請求が 2 回届いた。バッチは必ず途中で止まる。だから、どこからでも流し直せる形にしておく。
この記事の進み方
What — バッチが壊れる 4 つの形
バッチ(まとめて処理する仕事)と定期ジョブ(決まった時刻に動く仕事)は、画面の操作と違い、誰も見ていない時間に、大量のデータを相手に動きます。壊れ方には決まった形があります。
| 壊れ方 | 例 | 起きること |
|---|---|---|
| 途中で止まる | 3,200 件目で接続が切れる | 半分だけ終わった状態が残る |
| 流し直すと二重になる | 最初から流し直す | 終わった分がもう一度処理される |
| 2 つが同時に動く | 前回が終わる前に次が起動する | 同じ対象を 2 つが処理する |
| 止まったことに気づかない | 夜中にエラーが出るだけ | 翌朝、利用者からの連絡で知る |
どれも、「1 回だけ、最後まで、見ている人がいる」という前提が崩れたときに起きます。そしてバッチでは、この前提は必ず崩れます。
何も覚えていないバッチを、もう一度最初から流す。
1 回目: 1 〜 3,200 件目 済
3,201 件目で停止
2 回目: 1 〜 10,000 件目
→ 1 〜 3,200 件目は 2 回処理- 二重の処理
- 3,200 件
- 作る手間
- 無い
- 流し直しの判断
- 誰でもできる(が危険)
- –冒頭の事故はこれ。処理の結果が外に出る(メール・課金)と、取り消せない。
- –処理が DB の書き込みだけでも、合計を足すような処理なら二重に足される。
1 万件のうち 3,200 件で止まった。流し直し方で、結果が変わる。
何度流しても同じ結果になる形
いちばん強いのは 3 つ目です。対象ごとに「済」を記録し、済のものは飛ばす。こうすると、バッチを 1 回流しても 5 回流しても、各対象は 1 回だけ処理されます。これは冪等性を、バッチの単位に当てはめたものです。
-- 対象ごとの「済」は、処理の結果そのものに持たせる
-- 請求書の行があれば、その人のその月は済
INSERT INTO invoices (user_id, month, amount)
VALUES ($1, '2026-09', $2)
ON CONFLICT (user_id, month) DO NOTHING; -- 2 回目は何もしない
請求書の行に「利用者 × 月」の一意の制約を付けておけば、2 回目の作成は DB が拒否します。「済」を別に記録するより、結果そのものが済の印になるほうが、記録し忘れがありません。
冒頭の請求バッチを「何度流しても安全」にするために、最も効くものはどれですか?
2 つが同時に動かないようにする
定期ジョブは、前回が終わっていなくても、時刻が来れば次が起動します。処理するデータが増えて実行時間が延びると、ある日から重なり始めます。
重なりを防ぐには、ジョブの開始時に**「実行中」の印を取り、取れなければ起動しない**ようにします。DB のロックや、ジョブの管理の仕組みが持つ「同時に 1 つだけ」の設定を使います。何度流しても安全な形にしてあれば、重なっても結果は壊れませんが、同じ仕事を 2 倍の負荷でやることになります。
Why — なぜバッチは「最後まで動く」前提で書かれるのか
開発中は、最後まで動く
開発のときのデータは数十件で、バッチは数秒で終わります。途中で止まる機会がありません。本番の 1 万件、数十分の実行で初めて、接続の切断、デプロイ、メモリ不足に出会います。
しかも、本番のデータは毎月増えます。去年 10 分で終わったバッチが、今年は 2 時間かかる。実行時間が延びるほど、途中で止まる確率も、次の実行と重なる確率も上がります。
対象が、流している間に変わる
「有料会員全員に請求書を作る」バッチを流している間にも、新しい会員が入り、退会する人がいます。流し始めた時点の対象と、流し終えた時点の対象は違います。
流し直したときに対象が変わっていると、「前回の続き」が何を指すのか分からなくなります。処理の対象は、流し始めるときに確定させて記録します。「2026 年 9 月分の請求は、9 月 30 日 23:59 時点の有料会員」のように、条件を時刻で固定します。
見張るのは「終わったこと」
冒頭のバッチは、止まったときにエラーをログに出していました。しかし、ログを見る人がいない時間でした。
バッチの監視は、**「成功したら報告し、報告が来なければ知らせる」**形にします。バッチの最後に「終わった、1 万件処理した」と記録し、朝 6 時までにその記録が無ければ担当者に通知する。これなら、エラーで止まっても、起動されなくても、終わらずに待ち続けても、同じように気づけます。
夜間バッチの監視として、最も漏れが少ないのはどれですか?
演習 — まず自分で判断する
解説を読む前に、まず自分で判断してみてください。ここで一度詰まっておくと、 次の節の判断軸が「なるほど」ではなく「そう来たか」に変わります。
冒頭の請求バッチを、どう作り直しますか?
- 有料会員 1 万人。毎月増えていて、実行時間は今 40 分
- 請求書を DB に作り、PDF を添付したメールを送る。メール送信のサービスは冪等キーを受け付ける
- 夜 2 時に定期実行。担当者は朝 9 時に出社する
- 経理は、朝 8 時までに全員の請求書が出ていることを求めている
- · 途中で止まったあと、流し直して二重にならないか
- · 流している間に対象が変わったとき、どう扱うか
- · 止まったことに、朝 8 時より前に気づけるか
「バッチが止まったら、最初から流し直せばいい」と言う新人に、それが危ない理由と、流し直してよい形を説明してください
- 相手は、画面の開発の経験はあるが、バッチの運用は初めて
- 相手の担当するバッチは、ポイントを付与して、利用者に通知を送る
- 流し直してよいかを、相手が自分で判断できるようにしたい
読み終わりましたか?
読了にすると、これを前提とする記事がロードマップで開放されます。