銀行エンジニアリング 07:RESULT_UNKNOWN — なぜ再送してはいけないのか
応答が返ってこない送金を、もう一度送ってよいでしょうか。答えは「分かるまで送ってはいけない」です。二重送金を防ぐために、照会と条件付き再送をどう組み立てるかを学びます。
v8以降に実装した台帳・記帳エンジンなどを実際に動かし、正常時と異常時の両方から銀行システムの構造を学ぶ。
Prerequisite: BANKING SYSTEMLEARNING GOALS
このページで学ぶこと
- Timeoutが「失敗」ではない理由
- 照会(Settlement Inquiry)で事実を確かめる手順
- 再送してよい条件と、同じE2E IDを使う理由
PLAIN LANGUAGE
まず、ここだけつかむ
応答がない送金は、届いて決済された可能性があるため、すぐに再送してはいけません。
照会で決済システムの記録を確かめ、事実に合わせて状態を進めます。
未着が2回確認された場合だけ、管理責任者が同じE2E IDで再送できます。
DIFFICULT PARTS, STEP BY STEP
難しいポイントを、順番にほどく
専門用語を覚えることより、「なぜ必要か」「このシステムのどこで使うか」を理解することが目標です。
RESULT_UNKNOWN
処理されたかどうか分からない状態です。
分からないことを「失敗」と誤って扱わないためです。
通常の送信は IB008 で拒否され、照会が必要です。
Settlement Inquiry
決済システムへの状態の問い合わせです。
相手側の記録で事実を確かめるためです。
interbank.inquire()。STATUS_INQUIRY と STATUS_REPORT の電文が残ります。
End-to-End ID
送金人から受取人まで同じ支払を指す番号です。
再送しても同じ支払だと相手に分かるようにするためです。
end_to_end_id。決済システムはこの番号で重複を排除します。
Level 1 基礎:返事がないとき、何が起きたのか
送信して返事が来ないとき、可能性は少なくとも3つあります。どれなのかはMiniBankからは分かりません。
| 本当に起きたこと | ここで再送すると |
|---|---|
| 電文が決済システムに届かなかった | 1回目として届く(問題なし) |
| 届いて受理・決済されたが、返事だけが失われた | 同じ送金がもう1回行われ、顧客のお金が2回出ていく |
| 届いて拒否されたが、返事だけが失われた | 拒否された支払を再び送り、混乱を増やす |
Level 2 銀行業務:照会してから判断する
- 01送信(SENT)
- 02応答なし(TIMEOUT:NO_RESPONSE_WITHIN_DEADLINE)
- 03期限切れ処理(RESULT_UNKNOWN:TIMEOUT_UNRESOLVED_INQUIRY_REQUIRED)
- 04照会(STATUS_INQUIRY)
- 05決済システムの記録に合わせる(ACCEPTED・SETTLED / REJECTED / 未着)
| 照会の結果 | MiniBankの対応 |
|---|---|
| 受理・決済済み | ACCEPTED → SETTLED。決済の記帳を行う(CONFIRMED_BY_INQUIRY) |
| 拒否 | REJECTED。資金確保を取消して顧客へ戻す |
| 記録なし(未着) | RESULT_UNKNOWN のまま(NOT_RECEIVED_BY_CLEARING)。未着の照会回数を数える |
Level 3 システム:MiniBankでの実装(正常時)
- TIMEOUT または RESULT_UNKNOWN の支払に通常の送信を呼ぶと IB008 で拒否される(「先に照会せよ」)
- interbank.inquire() は決済システムの記録を end_to_end_id で探し、見つかれば状態を事実に合わせる
- 再送(resend)は、RESULT_UNKNOWN かつ照会で2回「未着」が確認された支払だけ、管理責任者が実行できる
- 再送は新しい支払ではなく、同じ end_to_end_id の再送信(RESEND_SAME_END_TO_END_ID)。送信回数(send_attempts)だけが増える
- 決済システム側も end_to_end_id で重複を排除し、同じ番号を2回受け取っても判定し直さず、二重に決済しない(duplicate_receipts が増えるだけ)
異常時:Settlement結果が分からないまま決済が走った
| 段階 | 内容 |
|---|---|
| 症状 | 決済バッチが PARTIAL。details に SETTLED_BUT_BANK_STATUS_UNKNOWN。画面の「決済システムとの差異」に1件 |
| 調査 | 支払詳細で、MiniBank側は RESULT_UNKNOWN、Simulator側は ACCEPTED・決済済みになっていることを確認する |
| 考えられる原因 | 応答電文の喪失、Gatewayの障害、期限設定の短さ |
| 真因(このケース) | 受取銀行(ひかり架空銀行)が応答を返さない。決済システムは受理しており、決済も実行された |
| 対応 | 照会する。SETTLED に進み、未決済送金から中央銀行当座預金への決済仕訳が記帳され、差異が消える |
| 再発防止 | 結果不明の件数を常に監視し、日次の締めの前に照会で解消する。自動再送は入れない |
Level 4 アーキテクチャ:分散した2つの帳簿と「Exactly-once」
MiniBankと決済システムは別々のシステムで、1つのトランザクションでは更新できません。ネットワーク越しでは「必ず1回だけ届く」ことを保証できないため、①送る側は結果が分かるまで勝手に再送しない、②受け取る側は同じ番号を重複として無害化する、③あとで両方の帳簿を照合する、の3つを組み合わせて、実質的に1回だけ処理された状態を作ります。
v9では①が IB008 と再送条件、②が clearing_records の end_to_end_id 主キー、③が interbank.reconcile() の clearing_exceptions に当たります。
どこを確認すればよいか
- 管理画面の「結果不明」件数
- 支払詳細:送信回数・未着照会回数・Simulator側の記録
- 決済バッチの unconfirmed_count
CHECK YOUR UNDERSTANDING
3問で理解チェック
答えを頭の中で考えてから、各項目を開いて確認してください。
Q1TIMEOUTの支払に「送信」を押すとどうなりますか?
IB008で拒否され、照会を求められます。
Q2再送が許されるのはどんなときですか?
RESULT_UNKNOWNで、照会で2回未着が確認され、管理責任者が行うときです。
Q3再送で新しいE2E IDを使わないのはなぜですか?
実は届いていた場合に、決済システムが重複として扱えるようにするためです。
完全に暗記する必要はありません。大切な考え方を説明できそうなら押してください。
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-idempotency-integrity冪等性と At-least-once+冪等
- RELATED LESSON/docs/reliability-incident信頼性設計と障害対応
- CURRENT IMPLEMENTATION
supabase/migrations/20260924110000_v9_interbank_simulator.sqlinterbank.inquire / interbank.sweep_timeouts照会と結果不明の扱い - CURRENT IMPLEMENTATION
supabase/migrations/20260924110000_v9_interbank_simulator.sqlinterbank.sim_rules / interbank.sim_clearing_receive架空の決済システムの判定と重複排除 - CURRENT IMPLEMENTATION
scripts/banking/v9-interbank.test.mjs正常・重複・拒否・Timeout・結果不明・再送・返却・部分失敗のDBテスト