「毎日深夜に売上データを集計したい」
「月末に請求データをまとめて作成したい」
「外部システムからCSVを定期的に取り込みたい」
こうした業務システムでよく利用されるのが、バッチ処理です。
バッチ処理とは、ユーザーが画面から一件ずつ操作するのではなく、決められたタイミングや条件で複数のデータをまとめて処理する仕組みです。
例えば、
- 毎日0時に売上を集計する
- 毎朝6時に在庫データを連携する
- 毎月末に請求書を作成する
- 1時間ごとに未送信メールを配信する
- 毎晩バックアップを実行する
といった処理があります。
一見すると、
「決められた時間にプログラムを動かせばよい」
ように見えます。
しかし、実際のバッチ処理設計では、
- 処理途中でエラーになったらどうするか
- 同じバッチが二重起動したらどうするか
- 再実行したときに同じデータを二重登録しないか
- 100件中99件まで成功した場合どうするか
- 処理時間が予定より長くなったらどうするか
- 失敗したことを誰がどう知るのか
まで考える必要があります。
結論からいうと、安定したバッチ処理を設計するには、
定期実行の方法だけでなく、対象データ・排他制御・冪等性・再実行・ログ・監視・障害復旧をセットで設計すること
が重要です。
この記事では、業務システムでバッチ処理を設計するときの基本から、具体的な障害対応まで分かりやすく解説します。
バッチ処理とは
バッチ処理とは、一定量のデータや処理をまとめて自動実行する方式です。
例えば、ECシステムでその日の売上を集計するとします。
ユーザーが毎日、
「今日の売上を集計する」
というボタンを押すこともできます。
しかし、毎日必ず行うのであれば、
毎日23:59
↓
その日の注文を抽出
↓
売上を集計
↓
集計結果を保存
という処理を自動化した方が効率的です。
このような処理がバッチ処理です。
バッチ処理とリアルタイム処理の違い
業務システムでは、すべての処理をバッチ化するわけではありません。
その場で処理すべきものと、後からまとめて処理できるものを分けます。
リアルタイム処理
ユーザーの操作直後に結果が必要な処理です。
例えば、
- ログイン
- 在庫確認
- 商品購入
- 予約確定
- 支払処理
- 顧客情報更新
などです。
バッチ処理
一定時間ごと、または大量データをまとめて処理しても問題ない業務です。
例えば、
- 日次売上集計
- 月次請求作成
- 定期メール配信
- CSV連携
- データバックアップ
- 古いデータの削除
- 外部APIとの定期同期
などです。
どちらが優れているというものではありません。
業務上、
「いつまでに結果が必要なのか」
を基準に選びます。
バッチ処理が使われる代表的な業務
業務システムではさまざまな場面でバッチ処理が利用されます。
売上集計
毎日の注文や売上を集計します。
例えば、
注文データ
↓
日付別に集計
↓
店舗別売上
↓
商品別売上
↓
集計テーブルへ保存
といった処理です。
請求データ作成
月末に対象取引をまとめて請求データへ変換します。
例えば、
当月の未請求売上
↓
顧客単位で集計
↓
請求データ作成
↓
請求書PDF作成
という処理です。
外部システム連携
販売管理システムや会計システムなどから定期的にデータを取得します。
例えば、
毎日6時
↓
外部システムからCSV取得
↓
データ検証
↓
自社データベースへ登録
という形です。
メール送信
送信予定となっているメールを一定間隔で処理します。
例えば、
10分ごと
↓
未送信メール取得
↓
メール送信
↓
送信済みに更新
とします。
データメンテナンス
古い一時データなどを定期的に削除することもあります。
例えば、
90日以上前の一時ファイル
↓
削除
といった処理です。
バッチ処理の設計で最初に決める7つのこと
バッチ処理を設計するときは、まず次の項目を整理します。
1. 何を処理するのか
対象となる業務を明確にします。
例えば、
「前日の注文を集計する」
という処理です。
2. いつ実行するのか
例えば、
- 毎日1時
- 毎週月曜日
- 毎月1日
- 10分ごと
- 1時間ごと
などです。
3. どのデータを対象にするのか
例えば、
前日分
未処理
ステータス=確定済み
などの条件です。
4. どれくらいの件数を処理するのか
100件と100万件では設計が大きく異なります。
想定件数だけでなく、将来の増加も確認します。
5. 失敗したらどうするのか
- 全件やり直す
- 失敗したデータだけ再実行する
- 自動リトライする
- 管理者が手動で対応する
などを決めます。
6. 結果をどう確認するのか
正常終了したのか、何件処理したのかをログや管理画面で確認できるようにします。
7. 誰へ通知するのか
異常終了時に、
- メール
- Slack
- Teams
- 監視サービス
などで通知する方法を決めます。
バッチ処理の基本的な流れ
例えば、毎日1時に前日の注文を集計するバッチを考えます。
基本的には、
バッチ開始
↓
対象データ取得
↓
データ検証
↓
処理
↓
結果保存
↓
ログ記録
↓
正常終了
という流れです。
エラーが発生した場合は、
エラー発生
↓
エラー内容記録
↓
必要に応じてロールバック
↓
異常終了
↓
管理者へ通知
という処理を行います。
ポイントは、
正常終了だけでなく異常終了の流れも最初から設計すること
です。
定期実行はどのように行う?
バッチ処理では、処理を開始する仕組みが必要です。
代表的な方法には次があります。
cron
Linux環境などで広く使われる定期実行方法です。
例えば、
毎日2時にプログラムを実行する
といった設定ができます。
小規模なシステムではシンプルな方法です。
クラウドのスケジューラー
AWS、Google Cloud、Azureなどには、決められた時間に処理を起動するサービスがあります。
例えば、
スケジューラー
↓
サーバーレス関数
↓
バッチ処理
のような構成です。
ジョブ管理システム
多数のバッチ処理があり、
バッチA終了
↓
バッチB開始
↓
バッチC開始
といった依存関係を管理したい場合には、ジョブ管理の仕組みを利用することがあります。
重要なのはツール名ではなく、
実行時刻・依存関係・失敗時の扱いを管理できるか
です。
「毎日0時実行」だけでは要件として不十分
例えば、
「毎日0時にバッチを動かしてください」
という要件があったとします。
これだけでは、実装に必要な情報が不足しています。
確認したいのは、
- 0時になった瞬間のデータを対象にするのか
- 前日の23:59:59までを対象にするのか
- バッチ中に追加されたデータは対象にするのか
- タイムゾーンは何か
- 休日でも実行するのか
- 月末だけ処理が変わるのか
といった部分です。
特に日時条件は、後から不具合が出やすいポイントです。
対象期間は明確に定義する
例えば、
「昨日の注文」
を処理するバッチを考えます。
曖昧に、
現在時刻 − 24時間
としてしまうと、実行時刻がずれた場合に対象期間もずれる可能性があります。
業務要件として、
2026/07/30 00:00:00以上
2026/07/31 00:00:00未満
というように期間を明確にする方が安全です。
日次・月次集計では特に、
開始日時以上
終了日時未満
という考え方で期間を定義すると境界条件を整理しやすくなります。
タイムゾーンにも注意する
クラウド環境では、サーバーやスケジューラーがUTCを基準に動作していることがあります。
一方、日本企業の業務では日本時間を基準にするケースが多いでしょう。
例えば、
日本時間 0:00
と
UTC 0:00
では9時間違います。
そのため、
- システムで使う基準タイムゾーン
- データベースで保存する時刻
- スケジューラーのタイムゾーン
を明確にします。
バッチ処理では二重起動を防ぐ
バッチ処理で重要なのが排他制御です。
例えば毎日1時に実行する処理が、何らかの理由で2回起動したとします。
1回目
↓
請求データ100件作成
2回目
↓
同じ請求データ100件作成
となれば二重請求につながる可能性があります。
そのため、
「すでに同じバッチが実行中なら、新しい処理を開始しない」
という制御を検討します。
排他制御の考え方
例えば、
バッチ開始
↓
実行中フラグ確認
↓
すでに実行中
→ 終了
未実行
↓
ロック取得
↓
処理開始
↓
処理終了
↓
ロック解除
という設計があります。
ただし、処理途中でサーバーが異常終了すると、
「実行中のままロックが残る」
可能性もあります。
そのため、
- ロックの有効期限
- 実行開始日時
- 異常終了時の解除方法
なども考える必要があります。
冪等性を意識して設計する
バッチ処理で非常に重要な言葉が「冪等性」です。
冪等性とは簡単にいうと、
同じ処理を複数回実行しても、結果が不必要に重複しない性質
です。
例えば請求データ作成バッチを再実行したとします。
1回目
→ 請求100件作成
2回目
→ 同じ請求100件を追加作成
では問題です。
理想は、
1回目
→ 100件作成
2回目
→ すでに作成済みなので0件
となることです。
処理済みフラグだけに頼らない
例えば、
processed = false
のデータを取得し、
処理後に、
processed = true
へ変更するとします。
シンプルですが、
データ登録
↓
processed更新前にエラー
となった場合、
実際の処理は完了しているのに未処理扱い
になる可能性があります。
再実行すると二重処理になります。
そのため、
- 一意制約
- 処理ID
- ステータス
- トランザクション
なども組み合わせて設計します。
バッチ処理ではトランザクション範囲が重要
例えば100件のデータを処理するとします。
全件を1トランザクションにする
100件すべて成功
↓
コミット
1件でも失敗
↓
全件ロールバック
という方式です。
整合性は保ちやすい一方、処理件数が多い場合は長時間トランザクションになる可能性があります。
1件ごとにコミットする
1件処理
↓
コミット
1件処理
↓
コミット
という方式です。
途中で失敗しても、それまで処理したデータは残ります。
ただし、
「どこまで処理されたか」
を管理する必要があります。
どちらが正しいというわけではありません。
業務上、
全部成功しなければ意味がないのか、それとも一部成功でもよいのか
を基準に決めます。
エラー時に全件止めるか、続行するか
CSV取込バッチで1,000件処理するとします。
500件目でデータ不備があった場合、
全件停止
1件でもエラーがあれば終了します。
向いているケース:
- データ全体の整合性が重要
- 一部だけ登録されると業務上困る
エラー行だけ除外して続行
500件目だけエラーとして記録し、501件目以降を処理します。
向いているケース:
- 各データが独立している
- 正しいデータだけでも処理したい
この判断も要件定義で決める必要があります。
自動リトライは何でも行えばよいわけではない
外部API呼び出しなどでは、一時的な通信エラーが発生することがあります。
例えば、
API呼び出し
↓
タイムアウト
↓
数秒待つ
↓
再試行
という自動リトライは有効です。
一方、データ内容が間違っている場合、
何回実行しても失敗
します。
そのため、エラーを分けて考えます。
一時的なエラー
- ネットワークエラー
- 一時的なAPI障害
- タイムアウト
→ リトライを検討
恒久的なエラー
- 必須項目不足
- データ形式不正
- 存在しない顧客ID
→ リトライせずエラー記録
というように使い分けます。
リトライ回数には上限を設定する
無制限にリトライすると、障害時に同じ処理を延々と実行する可能性があります。
例えば、
1回目
↓
失敗
↓
10秒後に再試行
↓
失敗
↓
30秒後に再試行
↓
失敗
↓
1分後に再試行
というように、回数と間隔を決めます。
一定回数失敗したら、
異常終了
↓
管理者通知
へ切り替えます。
再実行を前提に設計する
「バッチは失敗しない」
という前提で設計すると、障害時の対応が非常に大変になります。
実際には、
- DB接続エラー
- ネットワーク障害
- 外部サービス障害
- データ不備
- ストレージ不足
- サーバー停止
などが起こる可能性があります。
そのため、
失敗する可能性があることを前提に、どう再実行するかを最初から決める
ことが重要です。
再実行方法には複数ある
全件再実行
対象期間をもう一度すべて処理します。
冪等性が十分に確保されていれば使いやすい方法です。
失敗分だけ再実行
エラーになったデータだけを再処理します。
大量データを扱う場合に効率的です。
指定期間を再実行
例えば、
2026/07/30分だけ再集計
と管理者が指定できる方法です。
日次・月次集計では便利です。
バッチ実行履歴を残す
運用時に重要なのが、バッチの実行履歴です。
例えば次のような情報を保存します。
- バッチ名
- 実行ID
- 開始日時
- 終了日時
- ステータス
- 対象件数
- 成功件数
- 失敗件数
- エラーメッセージ
- 再実行元ID
例えば、
バッチ名:daily-sales-summary
実行ID:JOB-20260731-001
開始:2026/07/31 01:00
終了:2026/07/31 01:03
対象:12,530件
成功:12,530件
失敗:0
状態:正常終了
という形です。
これがあれば、
「昨日のバッチは動いたのか」
を確認できます。
ログには何を残す?
バッチログでは、単に、
「処理開始」
「処理終了」
だけでは障害調査に不十分なことがあります。
例えば、
- 実行ID
- バッチ名
- 対象期間
- 対象件数
- 処理件数
- 処理時間
- エラー対象ID
- エラー内容
などを記録します。
ただし、ログへ個人情報やパスワード、秘密情報などを無制限に出力しないよう注意します。
ログも情報資産の一つとして扱います。
正常終了も監視する
監視というと、
「エラーが出たら通知する」
ことだけを考えがちです。
しかし、バッチ処理では、
そもそもバッチが起動しなかった
ケースもあります。
例えばスケジューラー設定が壊れていた場合、
エラーすら出ない
可能性があります。
そのため、
「毎日2時までに正常終了ログが存在するか」
など、正常に実行されたこと自体を監視する考え方も重要です。
処理時間の異常も監視する
通常5分で終わるバッチが、
30分
60分
かかっている場合、何らかの問題が起きている可能性があります。
例えば、
- データ件数急増
- DB負荷増大
- API遅延
- インデックス不足
などです。
エラーだけでなく、
「想定時間内に終わっているか」
も監視対象にします。
バッチ処理が長時間化したらどうする?
データ量が増えると、最初は5分だった処理が数時間かかるようになることがあります。
その場合は、
- 対象データを分割する
- 並列処理する
- DBクエリを改善する
- インデックスを見直す
- 一括取得せずページングする
- 前回以降の差分だけ処理する
などを検討します。
大量データは分割して処理する
例えば100万件を一度にメモリへ読み込むと、サーバー負荷が高くなります。
そこで、
1〜1,000件
↓
処理
1,001〜2,000件
↓
処理
というようにチャンク単位で処理します。
これによりメモリ使用量を抑えられます。
また、途中から再実行しやすくなる場合もあります。
並列処理は速いが注意も必要
大量データを、
1処理ずつ
ではなく、
10処理同時
にすれば高速化できることがあります。
しかし、
- DB接続数
- 外部API制限
- 同じデータへの同時更新
- 処理順序
などの問題があります。
単純に並列数を増やせばよいわけではありません。
特に外部APIにはレート制限がある場合があるため注意します。
前回成功時点を保存する方法
外部データ同期では、
「毎回すべて取得する」
より、
前回成功日時以降
だけ取得した方が効率的な場合があります。
例えば、
前回成功:2026/07/30 10:00
↓
今回
↓
2026/07/30 10:00以降の更新データ取得
という方法です。
ただし、前回成功日時をいつ更新するかは重要です。
処理途中で失敗したのに成功日時だけ更新すると、未処理データが飛ばされる可能性があります。
【具体例】毎日売上を集計する日次バッチ
ECシステムの売上集計を例にします。
要件
毎日1時に前日の確定注文を集計する。
対象
前日0時以上
当日0時未満
かつ、
ステータス=支払済み
の注文。
処理
注文取得
↓
店舗別集計
↓
商品別集計
↓
集計テーブル保存
二重実行対策
集計日+店舗IDなどへ一意制約を設定。
同じ日の集計データを重複登録しない。
エラー時
処理失敗
↓
トランザクションをロールバック
↓
異常ログ記録
↓
管理者通知
再実行
対象日を指定して再実行可能。
このように正常系だけではなく、
「二重実行・障害・再実行」
までセットで設計します。
【具体例】CSV一括取込バッチ
取引先から毎日CSVを受け取り、商品情報を更新するケースです。
フロー
CSV取得
↓
ファイル形式チェック
↓
1行ずつ検証
↓
正常データ更新
↓
エラーデータ記録
↓
処理結果保存
例えば、
総件数:10,000件
成功:9,980件
失敗:20件
とします。
管理者にはエラー20件だけ確認してもらいます。
この場合、
「1件エラーがあれば全件失敗」
ではなく、正しいデータは処理する設計です。
どちらを選ぶかは業務要件次第です。
【具体例】請求書作成の月次バッチ
月末に請求書を作成するケースを考えます。
対象
- 当月売上
- 未請求
- 取引確定済み
処理
未請求データ取得
↓
顧客ごとに集計
↓
請求データ作成
↓
請求明細作成
↓
対象売上を請求済みに変更
このバッチで最も避けたいのは二重請求です。
そのため、
- 請求済みチェック
- 一意制約
- トランザクション
- 冪等性
- 実行履歴
を慎重に設計します。
バッチ処理を管理画面から手動実行できるようにする?
障害対応を考えると、管理画面から再実行したい場合があります。
例えば、
対象日:2026/07/30
[再集計]
という操作です。
便利ですが、誰でも実行できるようにすると危険です。
そのため、
- 管理者だけ利用可能
- 実行前に確認
- 同時実行防止
- 操作ログ保存
などを検討します。
高リスクなバッチでは、手動実行自体をシステム管理者へ限定することもあります。
バッチ処理で障害が起きたときの基本対応
障害時には慌てて再実行するのではなく、まず現在の状態を確認します。
1. どこまで処理されたか確認
例えば、
1万件中5,000件まで成功
なのか、
トランザクションで全件ロールバック
なのかによって対応が変わります。
2. 原因を確認
- データ不正
- DB障害
- API障害
- プログラム不具合
- 容量不足
などを確認します。
3. 再実行方法を判断
- 全件再実行
- 失敗分だけ再実行
- データ修正後に再実行
などを選びます。
4. 業務影響を確認
例えば請求バッチが失敗していれば、請求書発行が遅れる可能性があります。
技術的な復旧だけでなく、業務影響も確認します。
【コピペ用】バッチ処理設計チェックリスト
バッチ処理を設計するときは、次の項目を整理すると要件をまとめやすくなります。
基本情報
- バッチ名:
- 処理目的:
- 実行頻度:
- 実行時刻:
- 休日も実行するか:
対象データ
- 対象テーブル・データ:
- 抽出条件:
- 対象期間:
- 想定件数:
- 最大件数:
処理
- 処理内容:
- 処理順序:
- 外部API利用:
- 外部ファイル利用:
- 後続バッチ:
二重実行
- 同時実行を許可するか:
- 排他制御方法:
- 二重登録防止方法:
エラー
- 1件エラー時に全体停止するか:
- エラー行だけ除外するか:
- 自動リトライするか:
- リトライ回数:
- リトライ対象エラー:
再実行
- 全件再実行可能か:
- 指定日再実行可能か:
- 失敗分だけ再実行可能か:
- 冪等性を確保しているか:
トランザクション
- 全件単位:
- 1件単位:
- 一定件数単位:
- ロールバック範囲:
ログ
- 開始日時:
- 終了日時:
- 対象件数:
- 成功件数:
- 失敗件数:
- エラー内容:
- 実行ID:
監視
- 異常終了通知:
- 未実行監視:
- 長時間実行監視:
- 通知先:
このチェックリストを埋めると、単に「毎日動かすプログラム」ではなく、運用まで考えたバッチ処理にしやすくなります。
バッチ処理設計でよくある失敗
正常系しか考えていない
最初の実装では正常に動いても、障害発生時に復旧できなくなります。
失敗・再実行まで要件として設計します。
再実行すると二重登録される
冪等性がないバッチでは、障害復旧が非常に難しくなります。
重要なバッチほど、何度実行しても重複しない設計を検討します。
実行履歴が残っていない
「昨日のバッチは実行されたのか」が分からなくなります。
実行単位の履歴を保存すると運用しやすくなります。
ログが多すぎて原因が分からない
大量のログを出力するだけでは、障害調査しやすいとは限りません。
実行IDなどを付けて、一回のバッチ処理を追跡できるようにします。
バッチが失敗しても誰も気づかない
ログだけ保存していても、人が毎日確認しなければ障害発見が遅れます。
重要なバッチは異常終了を通知します。
二重起動を想定していない
手動実行中にスケジュール実行されたり、サーバー側の再試行で二重起動したりする可能性があります。
排他制御を設計します。
大量データを一度にメモリへ読み込む
データ件数が増加するとメモリ不足になる可能性があります。
一定件数ずつ分割して処理する方法を検討します。
バッチ処理の設計に関するよくある質問
バッチ処理は何時に実行するのがよいですか?
業務によります。
夜間利用者が少ないシステムなら深夜に実行することがあります。
ただし、24時間利用されるシステムでは「夜間だから空いている」とは限りません。
処理負荷と業務上の締め時間を確認して決めます。
バッチ処理は毎回全データを処理した方がよいですか?
データ量が少なければシンプルな全件処理でも問題ない場合があります。
件数が多い場合は、
- 前回以降の差分
- 未処理データ
- 更新データ
だけを対象にすると効率化できます。
エラーが1件あったら全体を止めるべきですか?
業務要件によります。
請求など全体の整合性が重要なら停止する場合があります。
独立した顧客データの取込などでは、エラー行だけ除外して続行する方が適していることもあります。
バッチは何回までリトライすればよいですか?
固定の正解はありません。
ネットワークなど一時障害では数回リトライが有効ですが、データ不備では何度実行しても成功しません。
エラー種別を分け、回数上限を設定します。
冪等性は必ず必要ですか?
特に再実行が想定される重要なバッチでは、非常に重要です。
請求作成、メール送信、外部システム連携などは、二重処理の影響が大きいため慎重に設計します。
バッチ処理の結果を画面で確認できるようにした方がよいですか?
業務担当者や運用担当者が確認する必要がある場合は、管理画面を用意すると便利です。
例えば、
- 実行日時
- ステータス
- 成功件数
- エラー件数
を表示できます。
cronだけで十分ですか?
処理数が少なく依存関係も単純であれば十分なケースがあります。
一方、複数ジョブの依存関係、再実行、監視などが複雑になってくると、ジョブ管理やクラウドサービスを利用した方が管理しやすくなることがあります。
hiro-dev-labではバッチ処理を含む業務システム設計から相談できます
業務システムを開発していると、
「毎晩自動で集計したい」
「CSVを定期的に取り込みたい」
「月末に請求データを自動作成したい」
といった要求が出てきます。
しかし、実際には、
- いつ実行するか
- どのデータを対象にするか
- 二重実行をどう防ぐか
- エラー時にどうするか
- どこから再実行するか
- 誰へ通知するか
まで整理しなければ安定運用できません。
hiro-dev-labでは、単純な定期実行プログラムだけでなく、実際の業務フローを確認しながらバッチ処理の要件を整理できます。
例えば、
- 現在の業務フローのヒアリング
- As-Is(現在の業務)の整理
- To-Be(自動化後の業務)の整理
- バッチ対象業務の整理
- 実行タイミング設計
- データ抽出条件設計
- 排他制御
- 冪等性設計
- エラー処理
- 再実行設計
- ログ・監視設計
- 外部システム連携
- Webシステム開発
- 業務自動化
など、必要な範囲から相談できます。
例えば現在、
「毎月Excelを開いて売上を集計し、請求書を作成している」
のであれば、
売上確定
↓
月次バッチ
↓
請求データ作成
↓
請求書PDF作成
↓
担当者確認
という業務へ変更できる可能性があります。
単純なプログラム自動化ではなく、障害時も含めて継続運用できる仕組みにすることが重要です。
まとめ
バッチ処理の設計では、
「毎日何時に実行するか」
だけ決めても十分ではありません。
安定して運用するためには、
- 対象データ
- 実行タイミング
- タイムゾーン
- 排他制御
- 冪等性
- トランザクション
- エラー処理
- リトライ
- 再実行
- ログ
- 監視
- 障害通知
まで考える必要があります。
特に重要なのは、
バッチ処理は失敗する可能性があることを前提に設計すること
です。
正常に動いているときだけを見ると、バッチ処理は単純な定期実行に見えます。
しかし実際の業務システムでは、
「途中で止まった場合、どこから再開するのか」
「同じ処理をもう一度実行して問題ないのか」
「二重実行されたらどうなるのか」
を事前に決めておくことが、安定運用につながります。
日次集計、請求処理、CSV取込、外部API連携などをシステム化する場合は、定期実行だけでなく障害対応まで含めてバッチ処理を設計するとよいでしょう。