仕組みから学ぶ Web
応用読了目安 15 分#バッチ#定期実行#cron#冪等性#監視

バッチと定期ジョブ — 途中で落ちたとき、もう一度流して大丈夫か

夜間の請求バッチが 3,200 件目で止まった。朝、担当者が最初から流し直した。最初の 3,200 人に、請求が 2 回届いた。バッチは必ず途中で止まる。だから、どこからでも流し直せる形にしておく。

この記事の進み方

What — バッチが壊れる 4 つの形

バッチ(まとめて処理する仕事)と定期ジョブ(決まった時刻に動く仕事)は、画面の操作と違い、誰も見ていない時間に、大量のデータを相手に動きます。壊れ方には決まった形があります。

壊れ方例起きること
途中で止まる3,200 件目で接続が切れる半分だけ終わった状態が残る
流し直すと二重になる最初から流し直す終わった分がもう一度処理される
2 つが同時に動く前回が終わる前に次が起動する同じ対象を 2 つが処理する
止まったことに気づかない夜中にエラーが出るだけ翌朝、利用者からの連絡で知る

どれも、「1 回だけ、最後まで、見ている人がいる」という前提が崩れたときに起きます。そしてバッチでは、この前提は必ず崩れます。

Compare途中で止まったあと、どう流し直すか

何も覚えていないバッチを、もう一度最初から流す。

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 が拒否します。「済」を別に記録するより、結果そのものが済の印になるほうが、記録し忘れがありません。

確認 — ここまで読めたか

冒頭の請求バッチを「何度流しても安全」にするために、最も効くものはどれですか?

まず選ぶ(解答例は a〜d の記号で説明します)

2 つが同時に動かないようにする

定期ジョブは、前回が終わっていなくても、時刻が来れば次が起動します。処理するデータが増えて実行時間が延びると、ある日から重なり始めます。

重なりを防ぐには、ジョブの開始時に**「実行中」の印を取り、取れなければ起動しない**ようにします。DB のロックや、ジョブの管理の仕組みが持つ「同時に 1 つだけ」の設定を使います。何度流しても安全な形にしてあれば、重なっても結果は壊れませんが、同じ仕事を 2 倍の負荷でやることになります。

Why — なぜバッチは「最後まで動く」前提で書かれるのか

開発中は、最後まで動く

開発のときのデータは数十件で、バッチは数秒で終わります。途中で止まる機会がありません。本番の 1 万件、数十分の実行で初めて、接続の切断、デプロイ、メモリ不足に出会います。

しかも、本番のデータは毎月増えます。去年 10 分で終わったバッチが、今年は 2 時間かかる。実行時間が延びるほど、途中で止まる確率も、次の実行と重なる確率も上がります。

対象が、流している間に変わる

「有料会員全員に請求書を作る」バッチを流している間にも、新しい会員が入り、退会する人がいます。流し始めた時点の対象と、流し終えた時点の対象は違います。

流し直したときに対象が変わっていると、「前回の続き」が何を指すのか分からなくなります。処理の対象は、流し始めるときに確定させて記録します。「2026 年 9 月分の請求は、9 月 30 日 23:59 時点の有料会員」のように、条件を時刻で固定します。

見張るのは「終わったこと」

冒頭のバッチは、止まったときにエラーをログに出していました。しかし、ログを見る人がいない時間でした。

バッチの監視は、**「成功したら報告し、報告が来なければ知らせる」**形にします。バッチの最後に「終わった、1 万件処理した」と記録し、朝 6 時までにその記録が無ければ担当者に通知する。これなら、エラーで止まっても、起動されなくても、終わらずに待ち続けても、同じように気づけます。

確認 — ここまで読めたか

夜間バッチの監視として、最も漏れが少ないのはどれですか?

まず選ぶ(解答例は a〜d の記号で説明します)

演習 — まず自分で判断する

解説を読む前に、まず自分で判断してみてください。ここで一度詰まっておくと、 次の節の判断軸が「なるほど」ではなく「そう来たか」に変わります。

演習 — 設計判断を問う

冒頭の請求バッチを、どう作り直しますか?

与えられた条件
  • 有料会員 1 万人。毎月増えていて、実行時間は今 40 分
  • 請求書を DB に作り、PDF を添付したメールを送る。メール送信のサービスは冪等キーを受け付ける
  • 夜 2 時に定期実行。担当者は朝 9 時に出社する
  • 経理は、朝 8 時までに全員の請求書が出ていることを求めている
この軸で考える
  • · 途中で止まったあと、流し直して二重にならないか
  • · 流している間に対象が変わったとき、どう扱うか
  • · 止まったことに、朝 8 時より前に気づけるか
まず選ぶ(解答例は a〜d の記号で説明します)

演習 — 説明できるか

「バッチが止まったら、最初から流し直せばいい」と言う新人に、それが危ない理由と、流し直してよい形を説明してください

与えられた条件
  • 相手は、画面の開発の経験はあるが、バッチの運用は初めて
  • 相手の担当するバッチは、ポイントを付与して、利用者に通知を送る
  • 流し直してよいかを、相手が自分で判断できるようにしたい

読み終わりましたか?

読了にすると、これを前提とする記事がロードマップで開放されます。

この知識を使う実践ケース