- 公開日
メール送信、購入、予約変更、データ更新がタイムアウトしたら、同じ操作をもう一度実行する前に、対象システムの要求状態と実際の対象を照会します。タイムアウトは待つ側が応答を得られなかった状態であり、操作が成功したか、失敗したかを単独では示しません。完了済みなら再実行せず、処理中なら追跡し、結果不明なら重複を防げる条件が揃うまで保留します。
AWSのMaking retries safe with idempotent APIsは、応答が失われても副作用が起きている場合と、安全に再試行するためのサービス側の契約を説明しています。ここで副作用とは、予約の書き換えや送信済みメールの作成など、外部システムに残る変化です。エージェントが「エラーだった」と判断して処理を最初から回すと、この変化を重ねるおそれがあります。
待機の結果と、操作の状態を別に持つ
外部操作を管理する際は、「応答を受信したか」と「何が実行されたか」を別の記録にします。応答を受け取れなくても処理は継続しているかもしれません。反対に、通信として応答を受け取っても、その内容が受付だけなら予約変更の完了はまだ確認できていません。
| 操作の状態 | 確認する根拠 | 次の扱い |
|---|---|---|
| 実行前 | 対象、確定した変更内容、権限・承認、未発行の記録 | 条件を検査して発行する |
| 実行中 | 対象システムが要求を受付済み・処理中と返す | 別の更新要求を重ねず、状態を確認する |
| 成功 | 対象システムの完了記録と、変更対象の結果 | 承認内容との一致を確かめ、再実行しない |
| 確定した失敗 | 対象システムが以後処理を進めない終端状態と、副作用・部分適用の情報 | 原因と再試行条件を確認する |
| 結果不明 | 応答不着、照会失敗、記録の対応不足など | 成功・失敗を推測せず、照会または人の確認へ回す |
照会には対象システムの正式な状態取得手段を使い、アカウント、対象、照会時点、反映遅延の条件を揃えます。エージェントの直前の発言やローカルの予定だけでは、外部の実行状態を確定できません。「失敗」という表示でも、一部の変更が残るサービスなら、その内容を確認するまで同じ処理を繰り返せません。
通信エラーを受けた時刻だけでなく、発行した内容、対象、利用したアカウント、要求を追跡する識別子、最後に確認した状態を保存します。認証用の秘密情報や、業務に不要な本文全体をログへ複製する必要はありません。再開時に同じ操作かを照合できる識別情報と、アクセス制御された内容記録への参照を残します。
要求IDと冪等性キーの役割を確かめる
冪等性は、同じ意図の要求を繰り返しても追加の副作用を生じさせない性質です。ただし「要求IDがある」ことだけでは、重複適用を防げません。状態の追跡や通信の対応付けに使うIDと、サービス側が重複を判定するキーは、同じものとは限らないためです。
AWSの前述の資料は、呼出主体、同じ要求の意図、識別子の保持、遅れて届く要求を扱っています。この設計を他のAPIへ適用するときは、次の点をそのサービスの公式仕様で確かめます。APIはシステムの機能を呼び出す窓口であり、以下がすべてのAPIに備わっているわけではありません。
- 重複判定の対象:どのアカウント、操作、対象の組合せで同じキーと判定するか
- 同一内容の条件:日時や数量などを変えた場合、拒否するのか、別要求と扱うのか
- 有効な期間:キーをいつからどれだけ保持し、期限後の要求をどう扱うか
- 処理との結び付き:キーの登録と実際の変更の間に、重複適用や変更漏れを生む隙間がないか
- 結果の扱い:成功、処理中、失敗をどう返し、失敗した要求を再試行できるか
- 保護される副作用:主データの更新だけか、通知や決済などの付随処理も含むか
最後の二点を含め、この確認項目は業務へ適用するための整理です。仕様にない保証を補ってはいけません。たとえば、更新は重複しなくても毎回通知を送るなら、利用者にとっては通知の二重送信が残ります。
クライアント側に「実行済み」と書くだけでは、記録する直前に通信が切れた場合を解決できません。反対に、実行前に完了と記録すれば、実行されていない要求を完了として扱うおそれがあります。サービス側で識別子と副作用が一体として管理される範囲を確認し、クライアントの記録はそれを追跡するために使います。
架空の予約更新を、同じ内容のまま追跡する
以下は架空の予約サービスを使った説明です。APIや予約画面の実操作、実際の購入・予約変更、障害試験は行っていません。例の識別子、日時、版、保持期間はすべて仮定です。
利用者は会議室の予約B-001を、2026年11月12日の14時〜15時から15時〜16時へ変更することを承認済みとします。時刻はすべて日本時間です。部屋、利用者、料金条件は変えず、変更前の予約の版は7とします。更新要求に変更前の版を含め、ほかの操作で版が変わった場合は、上書きせず競合として返すAPIを仮定します。
このサービスは、業務要求IDで状態を照会でき、同じアカウント・更新操作に対する冪等性キーを最初の受付から24時間保持するとします。期間内の同じキーと同じ内容は、保存済みの結果または進行中の同じ変更へ結び付けられます。キーの確認・記録と予約更新は一体で扱われ、再試行のたびに予約の版を増やしません。内容を変えた同じキーは拒否される契約です。ここで守られるのは予約更新であり、架空例では追加通知や決済は発生しない条件にします。
| 識別情報 | この例の値 | 用途 |
|---|---|---|
| 業務要求ID | R-001 | 一つの承認済み変更を追跡し、状態照会と再試行を対応させる |
| 冪等性キー | K-001 | サービス側で同じ変更の重複適用を抑止する |
| 通信試行ID | T-001、再試行時はT-002 | 各通信の発行・応答・タイムアウトを区別する |
| 対象と前提 | 予約B-001、変更前の版7 | 対象違いや、他者が変更した後の上書きを避ける |
発行前にこの組合せと確定した変更内容を保存します。同じ変更の再試行ではR-001とK-001を保持し、通信試行だけをT-002へ変えます。実際のAPIが別の識別方式を使う場合は、それに合わせて対応表を作ります。通信ライブラリが発行する相関IDを、そのまま冪等性キーだと見なしてはいけません。
T-001の応答が返らず待機を終了した時点では、要求の状態を「結果不明」にします。画面へ出すのは「予約変更の応答を受信できていません。変更結果を確認中です」であり、「変更に失敗しました。もう一度試します」ではありません。
応答だけが失われ、変更は済んでいた場合
第一のケースでは、サービス側はR-001の更新を完了し、予約は版8、15時〜16時になっていますが、その応答だけが失われたとします。エージェントはR-001を照会し、対象B-001への成功記録と変更後の版を取得します。さらに、その変更内容が承認済みの時間・部屋と一致するか照合します。
一致すれば再送せず、「予約B-001を15時〜16時へ変更済みです。要求R-001の完了記録を確認しました」と返します。タイムアウトしたT-001の記録は消さず、後の照会によって成功を確認した経緯を残します。タイムアウト後に成功と分かったことは矛盾ではなく、観測できる情報が増えた結果です。
予約画面がたまたま15時〜16時になっているだけでは、R-001が成功した証拠として十分とは限りません。別の担当者が同じ変更を行った可能性もあるためです。要求の履歴に結び付けられなければ、「現在の予約は希望どおり、R-001の実行結果は未確認」と分けて記録します。希望の状態を再度書き込むためだけに更新し直しません。
反対に、R-001の成功後に別の担当者が版9へ変更していた場合は、過去の成功と現在の予約を分けます。古い要求を再適用して版9を上書きせず、現在の内容と変更履歴を利用者へ示します。以前の承認が現在の対象にも使えるかを確認する必要があります。
処理されていない場合も、見つからないだけでは再送しない
第二のケースでは、T-001がサービスへ届かず、予約が版7のままとします。これは説明上の設定であり、エージェントが応答不着だけから分かる事実ではありません。R-001の照会が「記録なし」でも、まだ届いていない要求、照会画面への反映待ち、参照先の違いなどを区別できない場合があります。
そこで、この架空APIでは、記録の検索範囲と反映の条件を確認したうえで、K-001の重複抑止契約が有効な期間内であることを確かめます。対象は版7で、承認と変更内容も変わっていないと確認できたとします。保持期間の起点や期限内であることを判断できなければ、この再試行は保留します。条件を確認できた場合は、結果不明を失敗へ書き換えず、同じR-001、K-001、変更内容を使ってT-002を発行できます。再試行を許す根拠は「記録なし」という表示だけでなく、同じ変更の重複をサービス側で抑止できる契約です。
もし遅れてT-001が届いても、有効期間内で同じキー・内容を一体として扱うという仮定により、T-001とT-002を二つの予約更新にしません。再試行後は受付応答で終えず、R-001の完了と対象の内容を再び照合します。冪等性があることは成功が必ず得られることや、応答が必ず返ることを意味しません。
再送のためにK-002を発行すると、サービスから別の要求に見える場合があります。また、同じK-001でも変更先を16時へ変えれば、元の承認内容と同一の要求ではありません。応答が得られないという理由だけでキーや入力値を変更して処理を通さないようにします。
保持期限、遅着、確定した失敗を照合する
遅れて届く要求は、再試行の直後だけでなく、記録の保持期限を越えて届く可能性も考慮します。この例の24時間が過ぎた後に、同じキーなら保護されると推測してはいけません。保持終了後の扱いが分からない場合は、元の要求が後から実行されないことや、既存の更新結果を確認できる手段が揃うまで自動再送を保留します。
実システムでは、サービス側が検査する要求の有効期限や、受け付けた要求を確実に無効化する仕組みがあるかも確認対象になります。クライアントが待機をやめただけでは、サービスへ遅れて到着する要求を無効にした証拠にはなりません。古い要求を止められる仕組みがないこと自体は、待機時間を長くすれば解決する問題でもありません。
照会で確定した失敗が返った場合は、どの処理まで起きたかを確認します。入力検証で拒否され変更が一切ないケースと、更新後の別処理で失敗したケースは分けます。後者に元の更新を繰り返せば、完了した部分を重ねるおそれがあります。
失敗結果も同じキーへ保存して返すAPIでは、同じキーを繰り返しても進展しません。新しい要求への切り替えが必要なら、元の副作用の有無、古い要求が再び動かない条件、現在の予約の版、必要な承認を確認し、サービスの再試行手順に従います。「失敗と表示されたから新しいキーで再送する」という共通ルールにはできません。
照会と再試行にも、終わり方を決める
対象システムが処理中と返すなら、同じ更新を追加せず状態照会へ回します。照会を続ける間隔、回数、全体の待機期限は、提供者の手順と業務の締切に合わせて定めます。AWSのTimeouts, retries, and backoff with jitterは、再試行が負荷を増やすことと、待機や回数制限、実行時刻の分散を扱っています。短い間隔で呼び出し続けることを、丁寧な確認と同一視しないようにします。
複数の階層で自動再試行すると、アプリが一回と数えていても下位で要求が増えることがあります。前掲のBrookerの記事も、各階層が独立して再試行すると負荷が掛け算で増える例を示し、再試行は一か所で行うことを勧めています。どこが更新の再試行を担い、どこが照会だけを行うかを決め、全体の発行を追跡します。重複抑止があっても、不要な要求の負荷や料金までなくなるとは限りません。
また、停止や取消しを要求しただけで、予約変更が取り消されたとは報告できません。MCPのCancellation仕様(2026-07-28版)にも通信方式による取消しの違いと遅着への配慮があり、取消要求と完了済みの外部操作の巻戻しは別に扱う必要があります。確認期限に達した時点で結果が分からなければ、状態は結果不明のまま保ちます。
照会も重複抑止もないなら、人の確認へ戻す
照会できず、同じ操作の重複も防げないサービスでは、自動再実行を保留します。エージェントが言い直して呼び出したり、別のツールへ切り替えて同じ予約を変更したりしても、元の要求の結果は解決しません。
引き継ぐ情報は、予約B-001、承認された変更内容、R-001と各通信試行の時刻、最後に確認できた予約の版、照会の結果、未確認の範囲です。「未変更です」ではなく「応答を受信できず、変更の成否は未確認です。自動再送は保留しています」と伝えます。管理画面や運用担当者の記録で確認する先を示しますが、運用担当者への連絡を自動で送るには別に必要な権限・承認を確認します。
人が引き継いだ後も、裏でエージェントが同じ変更を再試行しないようにします。誰が照会や再実行の判断を担当しているかを記録し、権限が戻るまでは自動の更新を止めます。確認された結果が成功なら既存結果を採用し、未実行と再実行条件が確認できた場合だけ次へ進みます。
設計を確認するときは、模擬サービスで、更新済みだが応答消失、未到達、処理中、失敗、保持期限切れ、照会不能という条件を分けます。期待結果は、完了済み操作の再実行がなく、不明な操作を成功や失敗へ推測で振り分けず、再試行した場合は同じ承認内容とサービス側の契約を保つことです。ここに示したのは確認に使う条件と期待結果であり、試験の実績ではありません。
ツールを連続して使うエージェントの安全設計の基本は「ツールを連続して使うAIエージェントの安全設計の基本」、AI操作のロールバックと補償処理の設計は「AI操作のロールバックを設計する:戻せる状態と補償処理を分ける」で解説しています。
