銀行エンジニアリング 08:重複・再試行・返却と照合
同じ依頼が2回届く、送信を再試行する、決済後にお金が戻ってくる。支払で起きる「正常ではないが想定内」の出来事と、それを帳簿で確かめる照合を学びます。
v8以降に実装した台帳・記帳エンジンなどを実際に動かし、正常時と異常時の両方から銀行システムの構造を学ぶ。
Prerequisite: BANKING SYSTEMLEARNING GOALS
このページで学ぶこと
- 重複依頼(Duplicate)の扱い
- 返却(Return)の仕訳と手数料
- 未決済送金の照合(GLと明細)
PLAIN LANGUAGE
まず、ここだけつかむ
重複依頼は同じIdempotency Keyで1件にまとめ、内容が違えば拒否します。
決済後の返却では送金額を顧客へ戻し、手数料は返しません。
未決済送金の勘定残高と未完了の支払の合計を照合します。
DIFFICULT PARTS, STEP BY STEP
難しいポイントを、順番にほどく
専門用語を覚えることより、「なぜ必要か」「このシステムのどこで使うか」を理解することが目標です。
Duplicate Request
同じ依頼が2回以上届くことです。
通信の再試行や二度押しで必ず起こるためです。
(依頼者, キー)の一意制約と IB009。
Return(返却)
決済後に受取銀行から資金が戻ることです。
受取口座の解約などで入金できない場合があるためです。
INTERBANK_RETURN_RECEIVED、状態は RETURNED。
GLと明細の照合
総勘定の残高と、その内訳の合計を比べることです。
記帳漏れや状態の食い違いを見つけるためです。
interbank.reconcile()。
Level 1 基礎:3つの「もう一度」
| 出来事 | 例 | MiniBankの対応 |
|---|---|---|
| 重複依頼(Duplicate) | 送金ボタンを2回押した | 同じIdempotency Keyなら同じ支払を返す。同じキーで内容が違えば IB009 |
| 再試行(Retry) | 応答がないので送り直したい | 結果が分かるまで送らない(前章)。未着が確認できたら同じ番号で再送 |
| 返却(Return) | 決済後、受取口座が解約済みと判明 | 受取銀行から資金が戻り、顧客預金へ入金する |
Level 2 銀行業務:返却の仕訳
決済が終わった支払が返却されると、中央銀行当座預金にお金が戻り、同じ額を送金人の預金へ入金します。MiniBank v9では送金手数料は返しません(手数料は送金サービスへの対価として、すでに役務が提供されたため)。
| イベント | 借方 | 貸方 |
|---|---|---|
| INTERBANK_RETURN_RECEIVED | 中央銀行当座預金 | 送金人の顧客預金 |
Level 3 システム:MiniBankでの実装
- 重複依頼:(依頼者, Idempotency Key)の一意制約、内容の fingerprint、advisory lock。同時に5回届いても支払は1件(DBテストで確認)
- 返却:決済済み(SETTLED)の支払にだけ起きる。interbank.apply_return() が記帳し、状態を RETURNED(BENEFICIARY_ACCOUNT_CLOSED)にする
- 被仕向送金:interbank.simulate_inbound() が他行からの入金を発生させ、INTERBANK_INBOUND_CREDIT で記帳する
- 照合:interbank.reconcile() が、未決済送金勘定の残高と、未完了の支払(AUTHORIZED・SENT・ACCEPTED・TIMEOUT・RESULT_UNKNOWN)の合計を比べる
異常時:GLと明細が合わない
| 段階 | 内容 |
|---|---|
| 症状 | 照合の status が MISMATCH(difference が0でない) |
| 調査 | 未決済送金勘定の仕訳と、未完了の支払一覧を突き合わせる |
| 考えられる原因 | 支払の状態だけが変わって記帳されなかった/記帳だけされて状態が変わらなかった |
| MiniBankでの防止 | 状態の更新と記帳は必ず同じトランザクションで行うため、片方だけが残ることはない。照合はそれを事後に確かめる安全網 |
Level 4 アーキテクチャ:補助元帳としての支払テーブル
未決済送金勘定(総勘定側の1つの残高)の内訳は、interbank.payments(支払ごとの明細)です。総勘定と補助元帳を別々に持ち、定期的に一致を確かめるのは銀行会計の基本形で、次のv10でより一般的な形に広げます。
どこを確認すればよいか
- 管理画面「他行為替 Simulator」の「未決済送金の照合」
- 支払詳細の「記帳(v8 Posting Engine)」から各仕訳のトレースへ
CHECK YOUR UNDERSTANDING
3問で理解チェック
答えを頭の中で考えてから、各項目を開いて確認してください。
Q1同じキーで金額だけ変えて受付するとどうなりますか?
IB009で拒否されます。
Q2返却で送金手数料も戻りますか?
v9では戻りません。
Q3未決済送金に含まれる状態はどれですか?
AUTHORIZED・SENT・ACCEPTED・TIMEOUT・RESULT_UNKNOWNです。
完全に暗記する必要はありません。大切な考え方を説明できそうなら押してください。
SOURCE TRAIL
根拠と関連教材
CURRENT IMPLEMENTATIONは確認したrepository内の実装です。HISTORICAL IMPLEMENTATIONは導入・修正の履歴で、後続migrationによる再定義があり得ます。RELATED LESSONは教材への案内で、実装の一次Sourceではありません。ASSUMPTIONは仮定、UNKNOWNは未確認を表します。
確認基点: d02eae8914f39cbf06bfe422dc39c71886f82b3e / 2026-09-11。稼働環境への適用確認: UNKNOWN。パス実在の自動検査と、記述した技術的事実の確認は別です。
Implementation Status: IMPLEMENTED IN MINIBANK(この教材が扱うコードの範囲)
- RELATED LESSON/docs/be-result-unknown再送の条件
- RELATED LESSON/docs/reconciliation照合と整合性検査
- CURRENT IMPLEMENTATION
supabase/migrations/20260924110000_v9_interbank_simulator.sqlinterbank.guard_transition / interbank.reconcile状態遷移の検査と未決済送金の照合 - CURRENT IMPLEMENTATION
supabase/migrations/20260924110000_v9_interbank_simulator.sqlinterbank.apply_return返却(支払ごとのサブトランザクション) - CURRENT IMPLEMENTATION
supabase/migrations/20260930130000_v17_reliability.sqlinterbank.run_settlement決済バッチ(支払ごとのサブトランザクション。v17で、書込停止中は部分失敗として記録せず RY001 で止める) - CURRENT IMPLEMENTATION
scripts/banking/v9-interbank.test.mjs正常・重複・拒否・Timeout・結果不明・再送・返却・部分失敗のDBテスト