冪等性と再試行の設計|Webhook/API連携で二重処理・取りこぼしを防ぐ

業務システムが外部サービスと連携すると、必ず起きるのが「二重に処理された」「届いていない」「順番が入れ替わった」といった問題です。
これは、運用の頑張りだけでは解消できません。システム側に再試行と冪等性(同じイベントを複数回受けても結果が同じになる性質)を組み込む必要があります。
本記事では、Webhook/API連携で処理を安定させるための設計を、実務の観点で整理します。

この記事で扱う論点
・二重処理が起きる理由(再送・タイムアウト・再実行)
・冪等キーと処理済み管理(データ構造)
・再試行(リトライ)とバックオフ、失敗時の運用
・監査ログと復旧(手作業に落とす条件)

Webhook/API連携の管理画面イメージ

連携イベント監視 最終更新 14:32
本日受信 128
再試行中 6
手作業確認 2
イベント
冪等キー
状態
操作
payment.succeeded
PAY-202512-088
処理済み
booking.updated
RSV-202512-021
再試行中
refund.created
REF-202512-004
要確認
14:32 LTE 82%

連携エラー確認

対象イベント refund.created
エラー内容 返金IDの照合待ち
現在の扱い 手作業キューに保留

1. 二重処理は“バグ”ではなく仕様として起きる

外部連携では、次の理由で同じイベントが複数回届きます。

つまり、二重送信を完全にゼロにするより、同じイベントが複数回来ても結果が変わらない設計にしておく方が現実的です。

2. 冪等設計の基本:処理済み管理(冪等キー)を“業務キー”で持つ

冪等性は、受信イベントに付与される一意ID(イベントID)だけでなく、業務側のキーでも守ると強くなります。
例として、次のようなキーを組み合わせて「処理済み」を持ちます。

冪等キー設計でありがちな失敗
・“時間”だけでキーを作り、近いイベントが衝突する
・業務キーが未確定なのに連携して、後から紐づかない
・再送イベントが「別イベント」として記録され、二重計上される

問い合わせや予約のようにステータス遷移が多い場合は、ステータス運用と整合する形で「同じ遷移を二回受けても同じ状態になる」ように作るのが基本です。

3. 再試行(リトライ)の設計:即時リトライと遅延リトライを分ける

再試行は、回数や間隔を決めずに続けると、外部側にも自社側にも負荷がかかります。
そのため、次のように段階を分けて設計します。

打ち切った後に必要なのは、「どこまで進んで、何が失敗したか」が分かるログです。ここは 監査ログ設計 と同様、追記・理由・エラー内容を残すと復旧が早くなります。

4. 失敗を“一覧化”する:手作業に落とすための画面とルール

再試行が尽きたら、現場が確認できる形に切り替える必要があります。最低限、次の情報を用意しておくと対応しやすくなります。

この「失敗一覧」は、問い合わせ管理の保存ビュー(フィルタ設計)と同じ発想で作ると、運用担当にも説明しやすくなります。

5. 連携が絡むときの“担当割当”の注意点

外部連携で問い合わせや予約が自動登録されると、担当割当も自動化されがちです。
ただし、担当割当には例外が多いため、自動・手動・混在の割当 を前提にし、連携登録時点では「仮割当」にしておく設計も現実的です。

業種別に注意したい連携例

物流(納品予約・受付枠)

予約枠や受付枠は、二重計上がそのまま現場の混乱につながります。業務の流れは 物流向け を前提に、冪等キーを「予約番号+日時+バース」など業務キー寄りで強化すると、重複登録を抑えやすくなります。

自動車販売・整備・タイヤショップ(予約・入庫・部品手配)

連携で予約や入庫が自動登録されると、二重登録が当日の段取りに影響します。業務の流れは 自動車販売・整備・タイヤショップ向け を前提に、冪等性と再試行を初期要件として含めておく方が安全です。

まとめ

外部連携は、二重処理と取りこぼしが起きる前提で設計すると安定します。
冪等キーで処理済み管理を持ち、再試行は段階化し、最後は手作業に移せる画面とルールを用意する。ログは追記で説明できる形にする。
これを最初から組み込んでおくことで、運用開始後の「なぜ二重になったのか」「どこで止まったのか」という確認にかかる時間を減らせます。インテンスでも、連携がある案件では、この設計を早い段階から要件に入れることを重視しています。

本記事は、Webシステム開発・スマホ自動変換「movo」・業務システム構築・フォームUX改善・EC支援を提供する 株式会社インテンスが、実際の開発プロジェクトで蓄積した知見をもとにまとめています。 株式会社インテンス(公式サイト)