死んだ日次締めを冪等に蘇らせる
目標
途中で死んだ日次締めを再実行して蘇らせ、二重反映も漏れもなく終えられるようになります。そして、勘定日付とシステム時刻を区別して締めの対象を選ぶ手を身につけます。
なぜ重要なのか
銀行システムには、時計が指す時刻(posted_at)と、帳簿が認める日付(biz_date)が別々にあります。勘定日付は締めバッチが終わって初めて進むため、締めが回っている間に入った取引は、どの日付に計上するかが曖昧になります。ここで起きる事故が、銀行のバッチ障害の大きな部分を占めます。
締めバッチは必ず冪等でなければなりません。同じ勘定日付に対して何回回しても結果が同じでなければならない、ということです。そうでなければ、バッチが死んだときに回し直すこと自体が新たな障害になります。再実行の方式は2つだけですが、すでに反映されたものの上にまだのものだけを足す増分方式は、「すでに反映されたものはすべて正しい」ことを前提とします。その前提が崩れている場合、増分方式には誤って入ったものを取り除く手段がありません。
今回の事案は次のとおりです。2026-08-25の日次締めバッチが22:10に開始し、途中で死にました。勘定日付2026-08-25の仕訳行240行のうち153行が反映された状態で、締めの出力物の残高合計が0ではありません。しかも、締めが回っている間、オンラインチャネルの1つが古い勘定日付を打ち続けていました。カットオフは2026-08-25T22:10:00で、翌営業日は2026-08-26です。
ステップ
/root/bank/gen_eod.pyを作成して実行し、/root/bank/eod.dbを作ってください。仕訳行372行と締めの履歴が入ります。/root/bank/eod_state.txtに7行書いてください。business_date=、eod_status=はsys_paramから、txn_total=、applied=、unapplied=はその勘定日付のtxnから、balance_rows=、closing_sum=はdaily_balanceから出します。posted_atがカットオフ以降で、かつbiz_dateが2026-08-25の行を、/root/bank/misdated.csvにtxn_id,posted_at,biz_date,eod_appliedのヘッダー行で書き出してください。そして/root/bank/misdated.txtにmisdated=、misdated_applied=、naive_after_cutoff=の3行を書いてください。最後の値は、勘定日付を見ずにposted_atだけで絞り込んだときの行数です。- その行の
biz_dateを2026-08-26に移し、eod_appliedも0に戻してください。すでに締めが終わった2026-08-24には手を触れないでください。 /root/bank/rerun_plan.mdに## 두 가지 재수행 방식、## 선택과 근거、## 멱등성을 어떻게 보장하나、## 중단 기준の4つの節で計画を書いてください(見出しは韓国語で、順に「2つの再実行方式」「選択と根拠」「冪等性をどう保証するか」「中止基準」という意味です)。「選択と根拠」の節には、再計算対象の行数を数字で入れてください。/root/bank/eod_rerun.shを作成して1回実行し、出力物を/root/bank/db_run1.csvにbiz_date,account,debit_total,credit_total,closing_balanceのヘッダー行で書き出してください。eod_runに成功の履歴も残してください。- 同じスクリプトをもう1回実行して
/root/bank/db_run2.csvを書き出したあと、/root/bank/idempotency.txtにrun1_rows=、run1_closing_sum=、run2_rows=、run2_closing_sum=、diff=の5行を書いてください。 sys_paramのeod_statusをCLOSEDに、business_dateを2026-08-26に進め、/root/bank/eod_report.mdに## 무엇이 멈췄나、## 계정일자가 왜 어긋났나、## 재수행을 어떻게 안전하게 만들었나、## 검증、## 남은 위험の5つの節でレポートを書いてください(見出しは韓国語で、順に「何が止まったか」「勘定日付はなぜずれたか」「再実行をどう安全にしたか」「検証」「残る危険」という意味です)。
参考
- カットオフの値はハードコードせず、
SELECT value FROM sys_param WHERE name='eod_cutoff'で読むと、条件がずれる余地が減ります。 - 締めの出力物の
closing_balanceの合計が0かどうかが、最も速い健全性のサインです。0でなければ、伝票の片側だけが反映された行があります。 - よくある間違い1: ステップ3で
posted_atだけで絞り込んでしまいます。正しく翌日付を打っていた別チャネルの取引まで紛れ込みます。 - よくある間違い2: ステップ4で
biz_dateだけを変えてeod_appliedをそのままにしてしまいます。その行は前回の締めの出力物に入ったまま、次の締めではスキップされます。 - よくある間違い3: ステップ6のスクリプトを
INSERTだけで組んでしまいます。2回目の実行で値が2倍になります。
締めが死んだ瞬間を再現する
/root/bank/gen_eod.pyを作成して実行し、/root/bank/eod.dbを作ってください。仕訳行372行と締めの履歴が入ります。
python3で/root/bank/eod.dbを作ります。テーブルはsys_param、txn、daily_balance、eod_runの4つで、仕訳行は372行です。
死んだ締めがどこまで進んだかを数える
/root/bank/eod_state.txtに7行書いてください。business_date=、eod_status=はsys_paramから、txn_total=、applied=、unapplied=はその勘定日付のtxnから、balance_rows=、closing_sum=はdaily_balanceから出します。
締めの対象はposted_atではなくbiz_dateで選びます。出力物のclosing_balanceの合計が0かどうかも見てください。0でなければ、伝票の片側だけが反映されています。
勘定日付が誤って打たれた取引を探す
posted_atがカットオフ以降で、かつbiz_dateが2026-08-25の行を、/root/bank/misdated.csvにtxn_id,posted_at,biz_date,eod_appliedのヘッダー行で書き出してください。そして/root/bank/misdated.txtにmisdated=、misdated_applied=、naive_after_cutoff=の3行を書いてください。最後の値は、勘定日付を見ずにposted_atだけで絞り込んだときの行数です。
条件は2つです。posted_atがカットオフ以降で、同時にbiz_dateが締め日である行。前の条件だけで絞り込むと、正しく翌日付を打っていた別チャネルの取引まで紛れ込みます。
勘定日付を翌営業日に移す
その行のbiz_dateを2026-08-26に移し、eod_appliedも0に戻してください。すでに締めが終わった2026-08-24には手を触れないでください。
biz_dateだけを変えてはいけません。すでに締めの出力物に反映された行が混ざっているので、eod_appliedも一緒に戻す必要があります。すでに締めが終わった前日には触れないでください。
再実行の方式を決めて根拠を書く
/root/bank/rerun_plan.mdに## 두 가지 재수행 방식、## 선택과 근거、## 멱등성을 어떻게 보장하나、## 중단 기준の4つの節で計画を書いてください(見出しは韓国語で、順に「2つの再実行方式」「選択と根拠」「冪等性をどう保証するか」「中止基準」という意味です)。「選択と根拠」の節には、再計算対象の行数を数字で入れてください。
4つの節が必要です。「選択と根拠」の節には再計算対象が何行かを数字で書き、「冪等性をどう保証するか」の節にはどのテーブルをどう扱うかを書いてください。
再実行スクリプトを作って1回回す
/root/bank/eod_rerun.shを作成して1回実行し、出力物を/root/bank/db_run1.csvにbiz_date,account,debit_total,credit_total,closing_balanceのヘッダー行で書き出してください。eod_runに成功の履歴も残してください。
手でSQLを打たず、スクリプトにしてください。2回目の実行が1回目と文字どおり同じでなければ、冪等性を試験できません。そして、1回目の出力物をCSVに書き出しておいてください。
もう1回回して冪等性を証明する
同じスクリプトをもう1回実行して/root/bank/db_run2.csvを書き出したあと、/root/bank/idempotency.txtにrun1_rows=、run1_closing_sum=、run2_rows=、run2_closing_sum=、diff=の5行を書いてください。
同じスクリプトをそのまま再実行して、出力物を書き出し直してください。2つのCSVを行単位で比較した結果がdiffです。値が2倍になっていたら、消さずに足したということです。
締めを確定して勘定日付を進める
sys_paramのeod_statusをCLOSEDに、business_dateを2026-08-26に進め、/root/bank/eod_report.mdに## 무엇이 멈췄나、## 계정일자가 왜 어긋났나、## 재수행을 어떻게 안전하게 만들었나、## 검증、## 남은 위험の5つの節でレポートを書いてください(見出しは韓国語で、順に「何が止まったか」「勘定日付はなぜずれたか」「再実行をどう安全にしたか」「検証」「残る危険」という意味です)。
出力物を作ったことと、締めを確定したことは別の仕事です。sys_paramの締め状態と勘定日付を一緒に進めてください。そして、レポートの5つの節を書いてください。