【ITニュース解説】The Ledger Committed. Webhook Delivery Is Unconfirmed. What Should Retry?
2026年10月08日に「Dev.to」が公開したITニュース「The Ledger Committed. Webhook Delivery Is Unconfirmed. What Should Retry?」について初心者にもわかりやすく解説しています。
ITニュース概要
送金処理が完了しても通知(Webhook)の到達が不明な場合、金融操作自体は再試行せず、「送金済み」を伝える通知イベントのみを再送すべきだ。これにより二重送金を防ぎ、通知の確実性を確保する。受信側での重複判別も重要となる。
ITニュース解説
システムが重要な支払い操作を完了したにもかかわらず、その結果を外部システムに通知するためのWebhookという仕組みがうまく機能せず、通知が届いたかどうかが未確認になる状況は、ITシステム開発において頻繁に直面する課題の一つだ。このような時、「何を再試行すべきか」という判断は非常に重要になる。もし支払いの操作自体を再実行してしまうと、顧客の口座から二重に引き落とされたり、意図しない金融取引が発生したりする重大な問題に発展する可能性がある。一方で、単に通知だけを再送するのであれば、金融的な影響は少なく、より安全な選択肢となる。この記事は、この判断を正確に行うためのシステム設計とメカニズムについて解説している。
まず、支払い予約のプロセスを見てみよう。システム内で「支払い予約」が行われると、それは「元帳」(会計取引を記録する台帳のようなもの)に記録される。これは、利用可能だった金額を、もう使えない「予約済み」の状態に移動させる会計処理だ。この元帳への記録と同時に、「payout.createdイベント」という、支払いが発生したことを示すデータも作成される。これら「元帳への記録」と「イベントの作成」は、通常、データベースの「トランザクション」という仕組みを使って、一連のまとまった処理として扱われる。トランザクションとは、一連の作業を「すべて成功するか、すべて失敗して元に戻るか」のどちらかになるように保証する仕組みだ。このトランザクションが成功して確定(コミット)すると、「支払い予約が完了した」という状態と、「そのことを外部に通知する準備ができた」という意図が確定する。しかし、この時点では、実際に外部のシステムにWebhookが送られたわけではない。
Webhookによる外部への通知は、このデータベーストランザクションとは独立した、別のプロセスとして行われる。作成されたイベントは、一意のIDと、発生した時点での支払い情報を含むボディデータを持つ。このイベントを、実際に「特定の相手のシステムへ送る」という行為を「配信」と呼ぶ。配信が失敗した場合、システムは何度も通知を送り直そうとする(リトライ)。この時非常に重要なのは、何度通知を試みても、それは「同じ支払いイベント」に対する再送であるべきで、「新しい支払い操作」を勝手に作り出すべきではない、という点だ。例えば、一度支払い予約が完了したイベントが、後で支払い詳細が更新されたとしても、以前に送ろうとした通知の中身は変わらない。通知は「そのイベントが発生した時点」の情報を伝えるものだからだ。リトライ時も、イベントのIDや内容(ボディデータ)は同じままで、単に送信の試行だけが繰り返される。これにより、通知を受け取る側も、送られてきたものが同じイベントだと認識し、重複して処理するのを防ぐための仕組みを用意する必要がある。
実際にWebhookを外部に送信する役割を担うのは、システム内部の「ワーカー」だ。ワーカーは送信すべきイベントを見つけると、それを「予約」し、「送信開始の証拠」をデータベースに記録する。これは、万が一ワーカー自体が途中で停止しても、「送信を開始しようとした」という事実を残すためだ。その後、ワーカーは実際に相手のサーバーへHTTPリクエスト(Webhook)を送る。しかし、ネットワーク通信は常に不安定で、様々な問題が起こりうる。例えば、リクエストを送った直後にネットワークが切断され、ワーカーが相手からの応答を受け取れなかったとする。この場合、相手のシステムはすでにWebhookを受け取って処理を開始している可能性もあれば、何も受け取っていない可能性もある。そのため、単に「応答がなかった」というだけで「何も起こらなかった」と判断して、新しい支払いとして再送するのは非常に危険だ。相手がすでに処理しているにもかかわらず、再度同じ支払い操作を行ってしまうことになるからだ。HTTPの成功を示す応答コード(例えば200番台のステータスコード)も、あくまで「送信側のシステムが、相手のサーバーから正常に受け取ったという確認を得た」という限定的な意味しか持たない。相手のシステムでその情報が完全に処理され、ビジネス上の目的が達成されたことまでは保証しないのだ。
このような不確実性に対応するため、システムはリトライの回数に上限を設けている。上限に達しても成功しない場合、その通知は「デッドレター」(これ以上自動では送られない状態)となる。しかし、デッドレターになった後でも、承認された運用担当者が手動で「この通知を再送してほしい」と指示できる仕組みも存在する。この場合も、新たな支払い操作ではなく、既存のイベント通知を再送する。このような複雑な挙動は、システムを開発する上で非常に重要な部分であり、適切に機能するかどうかを厳密に「テスト」する必要がある。テストでは、支払い予約から通知失敗、そしてリトライを経て最終的に成功するまでの一連の流れを、実際に金融操作が重複しないことを確認しながら検証する。特に、リトライ時に元帳の記録が増えていないかなどを細かくチェックする。受け取る側のシステムも、送られてきた通知が「以前にも受け取ったものと同じ」かどうかを識別し、もし同じであれば重複処理を避けるための仕組み(重複排除)を用意する必要がある。これは、通知の署名を検証したり、独自の「受信箱」のような場所でイベントIDを記録したりすることで実現できる。
関連する概念として、「ペイアウト(支払い)」と「ペイイン(入金)」では、会計処理の完了と通知イベントの発生タイミングが異なる場合がある。例えば入金の場合、入金を受け付けたという通知が出たとしても、それがすぐに元帳に確定的に記録されたことを意味しないこともある。各システムがどのようにコミット(確定)するかの境界線を理解することが重要だ。また、「会計調整(Reconciliation)」というプロセスは、システム内部の会計データに不整合がないかをチェックするものであり、これも通知が送られたかどうかとは別の問題だ。会計上の差異が発見されたとしても、それが自動的にWebhookを再送したり、修正取引を行ったりするわけではない。
結局のところ、金融取引が元帳に記録された後にWebhook通知の配信が未確認になった場合、システムがリトライすべきなのは「保存されたイベントの配信」であり、「金融コマンド(支払い操作)の再実行」ではない。これにより、顧客の口座から二重に引き落とされたり、予期せぬ金融操作が発生したりするリスクを避け、金融取引の整合性を保ちつつ、堅牢な通知メカニズムを構築することが求められる。
文字数:1994文字