日次バッチの0件を欠損と決めない—対象日・実行予定・完了期限を分ける

,

日次レポートで過去の日付に「0件」と出ると、まず障害を疑いたくなります。しかし、前の対象日のデータを後日の朝に処理するバッチでは、結果がまだ存在しないこと自体は予定どおりかもしれません。ここで復旧処理を走らせると、本来の定期実行と重なり、二重処理や不要な外部呼び出しを招きます。

今回扱うのは、2026年9月20日の運用記録で確認した「実行予定前の0件を欠損扱いしない」という診断です。対象日と実行日を分けるだけでなく、いつから未完了を調査すべきかまで定義します。本記事はソフトウェアとデータ運用の解説であり、投資助言ではありません。市場の営業日や特定年の祝日を判定する記事でもありません。

対象日から実行予定と完了期限を確定し、期限前の0件は待機、期限到来後の未完了は調査へ分ける四段階

最近の取り組みで確認できたこと

9月20日の日次記録と同日の作業メモには、9月18日を対象とする銘柄評価・定量スコアが0件だった一方、9月21日08:00の回で処理予定と確認した経緯があります。そこで、観測時点の0件を欠損扱いしない判断を残しました。これは当時の運用予定の記録であり、その日時の市場営業日としての正しさを保証するものではありません。

確認できた成果は、日付のずれを踏まえた診断と運用判断です。9月21日の実行成功、保存結果の充足、以下で提案する期限監視の本番実装は、この記事の根拠資料では未確認です。「欠損ではない」と「完了した」は同義ではありません。予定前の状態には、次に確認する時刻を添えて残す必要があります。

既存記事との違いもここにあります。「予定件数・起動件数・完走件数を分ける」は処理段階別の計数、「日次バッチの欠損を対象IDで突合する」は不足対象の特定、「事後リターンは成熟日を待って判定する」は分析用データの成熟が主題でした。今回は、その手前の「この対象日は、いま完了を要求してよい時期か」を決めます。件数集計やID突合を置き換えず、監査対象へ入れる時刻の条件を追加します。

仕組みを分解する

まず、日付を一つの列へ押し込めないことから始めます。次の項目は、今回の診断を再現可能にするための設計案です。

| 項目 | 保存する意味 |
|—|—|
| `target_date` | どの日のデータを処理するか |
| `scheduled_at` | その対象日を処理する予定日時 |
| `deadline_at` | 成果物の完了確認を要求する期限 |
| `started_at` | 実際に処理が始まった日時 |
| `checked_at` | 状態を判定した観測日時 |

予定日時は開始の見込みであり、完了期限ではありません。期限には処理時間や許容する待ち時間を含めます。遅れて起動したからといって、実際の開始時刻を基準に期限を毎回後ろへ動かすと、遅延が永久に検出されません。予定変更は理由と旧期限を残します。

流れは四段階です。①対象日を固定する。②承認した運用予定から開始予定と完了期限を解決する。③同じ対象日・処理種別の成果物を確認する。④観測時刻と期限を比べて表示を決める。再実行日が変わっても対象日は変えません。対象日を「今日」で上書きすると、過去分の処理が今日の成果へ紛れ込みます。

Apache Airflowも、data intervalという処理対象期間と実際の実行時刻を分け、logical dateは対象期間の開始を示すと説明しています。[1] これは概念の参考であり、既存環境へAirflowを導入したという意味ではありません。

小さく再現する手順

本番ジョブを起動する前に、固定した時計で判定だけを試します。次の短い関数は、予定と期限が解決済みの一つの処理について、完了確認があるかを分類する例です。日時はタイムゾーン付きに統一します。Python公式文書でも、awareな日時と、時点を一意に特定できないnaiveな日時を区別しています。[2]

“`python
def classify(now, scheduled, deadline, verified):
if scheduled is None or deadline is None:
return "予定不明"
if deadline < scheduled:
raise ValueError("期限が開始予定より前")
if verified:
return "完了確認済み"
if now < scheduled:
return "開始予定前"
if now < deadline:
return "完了期限前"
return "期限到来・要調査"
“`

架空の処理を「翌日の08:00開始予定、10:00完了期限」と決め、結果は未確認で固定します。07:59なら開始予定前、08:00なら完了期限前、10:00ちょうどなら要調査です。期限の境界を曖昧にしないため、この例では「期限以上」を調査対象にしています。10:00は説明用の仮定であり、元の運用記録で確認した期限ではありません。

次に、成果物確認済み、予定未設定、期限の前後逆転を試します。日をまたいだ再確認でも対象日が変わらないこと、UTC表記と日本時間表記の同じ時点が同じ判定になることも確認します。この関数は起動済みかどうかを判定しません。「完了期限前」を「実行中」と表示せず、開始証跡は別欄に出します。

実際の入力には追加の前提があります。成果物を読めなかった場合は、未完了ではなく「確認不能」を別欄へ残します。認証失敗など明確な異常があるなら、期限前でも異常通知を出します。時刻の分類は欠損警告を急がないためのもので、分かっている障害を隠すためのものではありません。

確認指標

日次画面では、対象日ごとに次の三つを分けます。

  • **期限前の未完了数**:欠損率の分子へ入れず、待機として表示する。
  • **期限到来後の未完了数**:開始証跡、成果物、必要なら対象IDを調査する。
  • **予定不明・確認不能の数**:ゼロ件の正常系に混ぜず、監視情報の不足として扱う。

期限前を画面から消すのも避けます。対象日、観測時刻、予定、期限、次回確認を同じ行へ置けば、待機の理由を追えます。元の記録から採用する実測は対象処理が0件だったことに限定し、誤警報の削減率や運用改善の効果はまだ数値化しません。

失敗しやすい点と安全策

**過去の日付ならすべて遅延とする。** 対象日はデータの所属先であり、納品期限ではありません。開始予定と期限を解決してから判定します。予定が取得できないなら、適当な翌朝を補わず予定不明とします。

**休日らしい日を一律に対象外とする。** 起動日、データ対象日、データ提供側の更新条件は別です。カレンダーの推測ではなく、運用で承認した対応表を入力にします。表の出典と版も記録し、予定の妥当性は別途点検します。

**期限前の0件を成功へ変換する。** 待機は成功でも異常でもない中間状態です。再確認を予約し、期限を迎えた後も未完了なら要調査へ移します。逆に完了済みでも、期限後の完了なら遅延履歴を消さない設計が必要です。

**期限到来と同時に全件を再実行する。** 読み取りが一時的に失敗しただけかもしれません。まず観測の成否と実行状況を確かめ、実不足があれば対象を限定して復旧します。待機条件を追加しても、既存の重複防止や費用上限は外しません。

再現チェックリスト

  • [ ] 対象日と実際の実行日時を別項目にした
  • [ ] 開始予定と完了期限を別々に定義した
  • [ ] 予定の根拠と変更履歴を残せる
  • [ ] 期限直前・ちょうど・直後を固定時計で試した
  • [ ] 確認不能と正常な0件を区別した
  • [ ] 期限前でも明確な障害を通知できる
  • [ ] 待機行に次回確認時刻を付けた

次に改善するなら

次は、この時刻分類を日次画面へ読み取り専用で追加し、現行判定と並べて比較する段階です。予定の誤設定、期限の長すぎ・短すぎ、確認不能の扱いを観察してから通知へ接続します。本番監視の自動化や誤警報削減は、まだ達成済みとはしません。最初の改善は、「0件だから復旧する」から「いつの結果を、いつまでに必要とするか確かめる」へ確認の順序を変えることです。

参考情報

  • 作成根拠:2026-09-20の日次統合記録と同日の作業メモ。非公開資料のため、本文は公開せず診断の要点だけを一般化しました。
  • 公式資料の確認日:2026-09-21。予定の説明と実行成功の証明は分けて扱っています。

Sources

[1] https://airflow.apache.org/docs/apache-airflow/stable/core-concepts/dag-run.html — Apache Airflow: Data Interval
[2] https://docs.python.org/3/library/datetime.html — Python: Aware and naive objects


トップへ戻る