株式会社インテンス Webシステム活用ガイド

外部API連携の設計|Webhook・再送・冪等性で“二重処理”を防ぐ

APIやWebhookによる外部連携は、接続できた時点で完成ではありません。 通信のタイムアウト、同じイベントの再送、処理順序の逆転、一部だけ成功する状態は、運用開始後に起こり得ます。 この記事では、二重処理と取りこぼしを防ぎ、失敗時に安全に復旧するための設計を整理します。

この記事で扱う論点
・再試行できる失敗と、人の確認が必要な失敗の区別
・イベントIDと業務キーによる冪等性
・再試行の間隔、上限、保留キューへの移行
・部分成功とイベント順序の逆転への対応
・監視、手動再送、権限、監査ログ

1. 連携失敗を復旧方法ごとに分類する

連携エラーをすべて同じ失敗として扱うと、再試行してよい処理と、データ修正や設定変更が必要な処理を区別できません。 原因だけでなく、誰がどの方法で復旧するかまで分類します。

失敗の種類 主な例 基本対応
再試行できる一時的な失敗 未処理と確認できた通信失敗や、再試行を許す応答 連携先の仕様と二重処理対策を確認し、回数と間隔を制限して再試行
処理結果が不明 更新要求を送った後のタイムアウト、応答の切断 外部の処理結果を照会する。同じ操作の再試行が保証される場合は同じキーで再試行し、判断できなければ確認待ちにする
入力・形式エラー 必須項目不足、日付形式、コード不一致 再試行せず保留し、修正対象を表示
送信APIの認証・権限エラー APIキーの期限切れ、権限不足 管理者が設定を確認。元の処理結果と実行条件を確認してから再試行
受信Webhookの検証失敗 署名不一致、正当な送信元と確認できない通知 業務処理に渡さず拒否。原因確認後も、正当性を検証できた通知だけを処理する
部分成功 注文登録は成功し、在庫更新だけ失敗 成功済み処理を記録し、未完了部分だけ復旧
同じエラーを無制限に再試行すると、外部サービスへの負荷や二重登録を増やします。自動再試行の対象、上限回数、最終的に保留へ移す条件を先に決めます。

タイムアウトは、自社が応答を確認できなかったという事実であり、相手側で未処理だったことを意味しません。HTTP仕様の再試行に関する説明でも、冪等ではない要求の自動再試行には、処理の性質や未実行の確認が必要とされています。回数制限だけで二重処理を防げるわけではありません。

2. 同じ操作の再試行と、別の操作を区別する

Webhookや送信APIでは、送信元が応答を受け取れず、同じイベントを再送することがあります。 冪等性とは、同じ要求を繰り返しても、意図した作用が1回だけ行った場合と同じになる性質です。例えば注文を1件作成する要求の再試行で、注文が2件に増えないようにします。毎回の通信ログや応答内容まで、同じである必要はありません。

識別子の役割を分ける
・イベントID:受信した通知を識別する。連携先・アカウントなど、IDが一意になる範囲も持つ
・業務ID:注文番号、問い合わせ番号、予約番号など、処理対象を識別する
・操作ID:一度実行したい個々の操作を識別する。同じ操作の再試行では維持し、別の操作には別のIDを使う

業務IDと操作種別だけでは、同じ注文に対する複数回の部分返金や、予約内容の再変更を区別できません。例えば注文Aの返金操作R1を再試行する時はR1を維持し、追加の返金操作R2は別に記録します。金額や本文が同じという理由だけで、別の操作まで除外しないようにします。

送信APIで冪等キーを使う場合は、最初の送信前に操作IDと送信内容を保存します。同じキーで内容を変更してよいか、キーの有効期間、どの応答が保存されるかは連携先の仕様に従います。例えばStripeの冪等リクエストでは、同じキーで異なるパラメーターを送るとエラーになり、キーの保持にも条件があります。これをすべてのAPIに共通する仕様とみなさず、接続先ごとに確認します。

受信済みと、業務処理の完了を分ける

受信履歴にIDがあるだけでは、業務処理が終わったとは限りません。受信済み・処理中・完了・結果不明・確認待ちなどを区別し、同じ通知が来た時の動作を決めます。完了済みは二重実行せず、処理中は並列に開始しません。失敗や結果不明は、履歴があるという理由だけで除外せず、復旧対象にします。

二つの処理が同時に「未処理」と判定することもあるため、IDを検索してから登録するだけでは不十分です。データベースの一意制約や、処理状態を条件とした更新などで、同じ操作を同時に開始しない構成にします。外部への更新は自社のデータベース更新と同時に確定できるとは限らないので、外部の結果照会や冪等キーと組み合わせて復旧します。

状態遷移がある処理は、ステータス設計の実例状態遷移図の作り方も確認し、「確定済み」の予約に同じ確定通知が届いても、メール送信や在庫減算を二度実行しないルールを決めます。

3. 再試行は間隔、上限、終了後の扱いまで決める

再試行が可能と確認した処理について、待機間隔・上限回数・総経過時間を決めます。通信ライブラリーと自社の処理がそれぞれ再試行して、想定以上の回数になる場合もあるため、どこで制御するかを明確にします。

打ち切り後も元データを消去せず、「どこまで成功し、何が失敗したか」を確認できるようにします。 監査ログ設計と同様に、対象ID、処理段階、エラー、再試行回数、変更理由を追記で残します。復旧に必要な元データは閲覧権限と保存期間を定め、秘密情報や不要な個人情報を通常のログへ複製しません。

  1. 正当な要求と処理状態を記録する
    送信内容または検証済みの受信内容を、操作ID・イベントID・処理状態と関連付けます。
  2. 再試行の条件を確認する
    外部の処理結果と冪等性を確認し、再実行できる処理に間隔と上限を適用します。
  3. 上限到達後は保留キューへ移す
    担当者が検索できる状態にし、推奨操作を表示します。
  4. 確認後に復旧操作を行う
    再試行・内容修正・処理終了のどれが必要か判断し、実行者と結果を記録します。

Webhookの受領応答は、処理を引き継げる状態で返す

非同期で処理する構成例では、送信元や署名などを検証し、受信内容を再取得・再処理できる保存先へ記録してから、受領したことを応答します。保存に失敗したまま受領済みと返すと、その後に処理を引き継げません。受領応答と業務処理の完了を別に記録し、応答後の処理失敗は自社側でも検知・復旧できるようにします。

応答コードや再配信条件は送信元の仕様を確認します。例えばStripeのWebhook仕様には、署名検証、早い受領応答、重複配信、到着順が保証されない場合の扱いが示されています。受領済みの重複通知へ再応答する場合も、未完了の業務処理を完了済みへ変更しないことが必要です。

4. 部分成功と順序逆転を処理単位で管理する

複数システムを順に更新する処理では、一つ目だけ成功して二つ目が失敗することがあります。 全体を最初から再実行すると、成功済みの処理が重複する可能性があります。

後から届いた通知が新しい状態を表すとは限りません。連携先に版番号や順序の保証があればその定義に従い、なければ最新状態の照会や前提条件の確認を行います。同じ時刻のイベントや時計の差もあるため、受信時刻・発生時刻だけで順序を決めません。前提情報が不足する場合は確認待ちとし、待機期限と確認する担当者を決めます。

5. 監視画面には次に行う操作を表示する

監視画面にエラーメッセージだけを並べると、担当者は原因調査から始めることになります。 連携名、対象データ、失敗段階、再試行回数、最終エラー、推奨操作を一画面で確認できる構成にします。

再試行中3件
確認待ち2件
本日復旧8件
受注API/注文 A-1028 形式エラー 再試行 0回 内容を確認

上の件数・注文番号は説明用の架空データで、実際には操作できません。形式エラーの1件は「確認待ち2件」の一部です。「再試行中」「確認待ち」は現在の状態、「本日復旧」は当日の実績なので、3つの数字は合計しません。

通知条件と担当者は通知・リマインド設計、失敗一覧の検索条件は一覧画面の絞り込み設計と合わせて決めます。

6. 手動再送の権限と監査ログを決める

外部連携では、接続先が指定する認証・送信元確認・署名検証を行います。署名が一致しない受信データを、設定を直したという理由だけで業務処理へ流さず、正当性を再確認します。APIキーの保管と更新、必要に応じたIP制限、ログのマスキングも接続方式と一緒に決めます。

手動再送は処理結果を変更する操作です。実行できる権限を限定し、実行者、実行日時、対象、理由、変更前後の内容、結果を記録します。 同じ操作の再試行は元の操作IDを維持します。内容を変更する場合は、元の要求が実行済み・結果不明のどちらかを確認し、変更要求として扱うか、未実行の要求を修正するかを判断します。キーの保持期間を過ぎた場合も、同じキーなら常に重複を防げるとは限りません。権限と記録項目は権限・操作ログ設計も参照できます。

7. 業種別に確認したい連携例

ホテル(予約・決済・通知)

事前決済を予約確定の条件とする方式なら、決済結果を確認してから確定通知へ進めます。現地払いなら条件が異なるため、未決済を一律に異常扱いしません。ホテル向けシステム開発例予約カレンダーと申込の連動を参考に、予約・決済・通知の状態を分け、予約IDで関連付けます。

製造業・物流(受注・在庫・配送)

受注登録後に在庫引当や配送連携が失敗すると、社内では受注済みでも出荷側へ届いていない状態になります。 受注番号を共通キーにし、未連携の工程を検索できる一覧と再送手順を用意します。項目・コード変換は外部連携のデータマッピング設計で別に管理します。

自動車販売・整備(予約・入庫・部品手配)

予約や入庫が二重登録されると当日の作業枠に影響します。自動車販売・整備向けの業務例では、予約や入庫のIDに、個別の変更・部品手配の操作IDを関連付ける構成が考えられます。同じ手配の再試行と、別の部品の追加手配を区別します。

CSV、EDI、APIの方式選定、項目対応表、受入テストまで含む全体像は、外部連携(CSV/EDI/API)設計ガイドで確認できます。

まとめ

外部API連携では、失敗を分類し、同じイベントを複数回受けても結果を一件に保つ設計が必要です。 イベントID・業務ID・操作IDの役割を分け、受信済みと処理完了を区別します。再試行の可否、結果不明の確認方法、部分成功と順序逆転、手動復旧の権限を、連携先の仕様に合わせて定義します。公開前には同時受信・応答切断・処理途中の停止も試し、重複と未完了を確認できることを検証します。