本文へスキップ
SNAMO Logo
SNAMO
受付番号を基点に、AIエージェントの二重処理を防ぐポリシーエンジン、人間承認、最小権限、監査ログ、ガードレールを表現した技術イメージ

受付番号が守った、AIエージェントの二重処理を防ぐ仕組み

19 min read

始業直後の「ひだまり商事」の受注センターで、エンジニアの直人は、注文画面に残った「送信中」の文字を見つめていた。メールを読み取り、商品と数量を確かめて受注APIへ送るAIエージェントのミナは、返事が届かないまま立ち止まっている。

「注文は、もう登録されたのかな。それとも、まだなのかな」

「通信が切れただけなら、もう一度送ってもいいのでしょうか」

直人が迷うあいだ、ミナは新しい request_id を作ろうとしていた。けれど、それは一回ごとの通信を見分ける番号で、同じ処理の再送を見分ける受付番号とは役割が違う。trace_id も処理の道筋を追うための番号だ。必要なのは、同じ注文のお願いに同じ印を付ける Idempotency-Key だった。通信タイムアウトや自動リトライ、複数のAIエージェントの並列実行が重なる朝、受付番号の設計が、二重処理を防ぐ小さな受付台になろうとしていた。

この記事の答え

  1. 結論AIエージェントの二重処理は、同じ注文の再送に同じIdempotency-Keyを付けて防ぐ。
  2. 根拠受注APIがキーと処理結果を保存し、同じキーの再送には新規登録せず結果を再利用する。
  3. 最初の一歩まず注文ごとにUUID v4のIdempotency-Keyを発行し、通信障害後も同じキーで再送する。
01

第1章 朝の注文画面と、消えない「送信中」の文字

二重注文を確認するエンジニアと受注端末

第1章 朝の注文画面と、消えない「送信中」の文字 - 本文

始業直後、ひだまり商事の受注センターで、ミナの注文画面が「送信中」のまま動かなくなった。窓の外では、朝の光がビルのガラスに広がっていたが、直人の指はマウスの上で止まっていた。

ミナは、顧客のメールから商品名と数量、納期を読み取っていた。内容に間違いはない。あとは受注APIへ送り、「注文を受け付けました」という返事を待つだけだった。

「注文は、もう登録されたのかな。それとも、まだなのかな」

ミナの声は、いつもより小さかった。直人が画面を見直しているあいだにも、送信先との通信は戻らなかった。

「通信が切れただけなら、もう一度送ってもいいのでしょうか」

「それが、いちばん怖いんだ。届いていないなら再送が必要だけど、届いていて返事だけが消えたなら、同じ注文をもう一度登録してしまう」

直人は、受注APIの管理画面を開いた。注文一覧には、今朝届いたばかりの注文が一件だけ表示されていた。けれど、その一件が、ミナの最初の送信によるものかどうかは画面から分からなかった。

九時を少し過ぎたころ、ミナの自動処理が動いた。一定時間、返事がなければ、失敗したと考えてもう一度送る仕組みだった。ミナは同じメールを読み直し、同じ商品と数量を受注APIへ送り直した。

その直後、画面に緑色の通知が出た。

「注文を受け付けました」

直人は、ようやく息を吐いた。ところが、注文一覧を更新すると、同じ顧客名と同じ商品が二行に並んだ。注文番号だけが違っていた。

「……二つ、あります」

隣の席の由美が、椅子を近づけた。直人は片方を消そうとしたが、出荷準備の画面には、すでに二件とも連携されていた。

「まだ倉庫には流れていません。でも、片方を消すだけでは済まないかもしれません」

由美の声を聞き、直人の背中が固くなった。ミナは間違った商品を選んだわけではない。決められた手順を、二度繰り返しただけだった。

そのとき、代表電話が鳴った。受話器を取った由美の顔が、少しずつ曇っていく。電話の相手は、先ほど注文した顧客だった。

「確認のメールが二通届きました。商品も二つ届くのでしょうか」

由美は、落ち着いた声で確認すると約束した。電話を切ったあと、受注センターにはキーボードをたたく音だけが残った。

直人は二つの処理記録を並べた。最初の送信には、ある request_id が付いていた。再送には、別の request_id が付いていた。これは一回ごとの通信を見分ける番号なので、別の送信として扱われていた。

「でも、どちらも同じ注文ですよね。なぜ同じものだと分からないんですか」

ミナが尋ねた。直人は、画面の二本の線を指でたどった。

「trace_id は、処理がどの道を通ったかを見るための番号だよ。request_id は、その道を一回通ったときの番号。通信がやり直されれば、新しい番号になる」

「では、同じ注文のお願いに、同じ目印を付ける必要があります」

「そう。同じ処理のお願いを、何度送っても同じものだと分かる受付番号がいる」

その受付番号が、Idempotency-Key だった。ミナが受注APIへ送るHTTPリクエストのヘッダーに付ける番号で、サーバーは同じ番号を見つけたら、処理をもう一度実行せず、最初の結果を返せる。

しかし、今のミナは、送るたびに新しい request_id を作っていた。trace_id も処理のたびに変わり、同じ注文を結び付ける印は、どこにも残っていなかった。

「ミナは、受付番号を作っていなかったんだね」

直人は小さくうなずいた。画面の二つの注文は、ただの重複ではなかった。返事が届かない時間と、自動リトライの間に、同じお願いを守る仕組みがなかった結果だった。

倉庫への連携を止めるため、直人は一時停止のボタンを押した。ミナの画面から「送信中」の文字は消えたが、二つの注文番号は残ったままだった。直人はログを保存し、未出荷のまま片方を保留にした。

「次に送るときは、通信の一回分ではなく、注文そのものに番号を付けましょう」

ミナは返事をしなかった。代わりに、空白だった受付番号の欄が、直人のモニターに静かに表示された。

02

第2章 届かなかった返事と、二つになった注文

直人がRedisと受付番号の仕組みを確認する受注センター

第2章 届かなかった返事と、二つになった注文 - 本文

直人は、前日に二つになった注文の記録を見ながら、受注センターの画面に残る「送信中」の文字を見つめていた。メールを読み取り、商品と数量を確かめて受注APIへ送るAIエージェントのミナは、返事が届かないまま立ち止まっている。朝の窓から光が差しても、その文字だけは消えなかった。

「注文は、もう登録されたのかな。それとも、まだなのかな」

「通信が切れただけなら、もう一度送ってもいいのでしょうか」

ミナの声は、いつもより小さかった。直人は前日の倉庫画面を思い出した。同じ顧客、同じ商品、同じ数量の注文が二件並び、春子が手を止めた朝のことだ。

「失敗したのは、ミナの判断だけじゃない」

直人はログを開いた。最初の送信には一つの request_id と trace_id があり、再送には別の番号があった。別のエージェントが同じメールを読んだ記録にも、また違う番号が残っていた。

そのとき、隣の開発室から美緒が入ってきた。美緒は、社内の受注基盤を長く見てきたエンジニアだった。直人の机に並ぶログを見て、静かに椅子を引いた。

「同じ注文なのに、番号が全部ちがうね」

「はい。リトライするたびに、新しい request_id を付けています。処理の道筋を見る trace_id も、送るたびに変わります」

美緒は白い紙を二枚取り出した。一枚には「一回の配達」と書き、もう一枚には「同じお願い」と書いた。

「request_id は、一回の通信を見分ける番号なの。配達員が一度目に持つ伝票と、二度目に持つ伝票が別々になるようなものよ」

「では、同じお願いだと分かる番号は?」

「それが Idempotency-Key です。少し難しい名前だけれど、意味は受付番号。注文という一つのお願いに、一つの印を付けるの」

美緒は紙の「同じお願い」に、青い丸を描いた。

「最初に送るとき、ミナが自分で受付番号を作る。たとえばUUIDのように、ほかと重ならない番号ね。その番号をHTTPヘッダーの Idempotency-Key に入れて送るの」

直人は画面に入力してみた。

Idempotency-Key: a1b2c3d4-e5f6-7890-1234-567890abcdef

「返事が届かなかったら、どうしますか。同じ番号で、もう一度送るの。新しい request_id になっても、受付番号は変えない」

「受注APIは、同じ受付番号を見つけたら?」

「最初の処理をもう一度しないで、最初に保存した結果を返すのよ。注文が登録済みなら、その登録結果を返す。そうすれば、通信の返事だけが迷子になっても、注文は二つにならない」

美緒は、もう一枚の紙に小さな箱を描いた。箱の中には、受付番号と注文内容、処理の状態、返した結果が並んでいた。

「この箱は、処理結果を覚えておく場所。Redisのような仕組みに保存できるわ。ただし、同じ番号で商品や数量が変わったら、そのまま通してはいけない」

「同じ受付番号なのに、別の注文になってしまうからですね」

「そう。注文内容の指紋も一緒に比べるの。番号と内容が合わなければ、エラーにして止める。初回の処理がまだ動いている間に同じ番号が来たら、二つを同時に通さないことも大事よ」

直人は、前日のログをもう一度見た。通信の一部で遅延が起きた。受注APIでは登録が終わっていたのに、完了の返事だけが届かなかった。ミナは失敗だと思い、自動で再送した。その間に、別のエージェントも同じメールを読み、並列に注文を始めていた。

「タイムアウト、返事の欠落、自動リトライ、並列実行。同じ依頼を、別のエージェントが処理することも重なっていたんですね」

「ええ。『一度だけ実行して』とミナに頼むだけでは足りないの。下の通信やライブラリが再送することもあるから」

美緒は、机の端に置かれた記事の印刷物を指さした。そこには、AIエージェントの再実行と Idempotency-Key を扱った Zennの記事 が表示されていた。直人は文章を追いながら、仕組みの順番をノートに書いた。

「番号を作る。ヘッダーに入れる。受注APIが保存場所を確認する。初めてなら処理して、結果を保存する。もうあれば、保存した結果を返す……」

「その流れなら、ミナが迷っても、受付側が同じお願いを見つけられるね」

直人の胸に、昨日から残っていた重さが少しほどけた。失敗したミナを叱るだけでは、次の通信断を止められない。返事が届かなかったときほど、同じ処理だと分かる印が必要だった。

直人は、注文画面の「送信中」を見た。まだ不安はある。それでも、今度は手を止めなかった。

「ミナ、まず受付番号を作ろう。同じ注文を送り直すときは、その番号を変えない。受注APIにも、同じ番号を二度処理しない仕組みを置いてみよう」

「わかりました。やってみます」

窓のそばで、ミナの画面に新しい受付番号が表示された。小さな番号は、まだ一行の文字にすぎない。けれど直人には、それが二重処理の朝に置かれた、小さな受付台のように見えた。

03

第3章 古い台帳と、「同じお願いには同じ番号」という助言

RedisとIdempotency-Keyを確認する二人の技術者

第3章 古い台帳と、「同じお願いには同じ番号」という助言 - 本文

直人は、二重になった注文のログを抱えて、澄江のいる小さな会議室を訪ねた。窓の外では、受注センターの画面が青白く光り、ミナの「送信中」という表示だけが消えずに残っている。

澄江は古い障害記録を机に広げた。そこには、受注APIが注文を登録した直後に通信が切れ、返事を受け取れなかった記録があった。

「返事がないからといって、処理が失敗したとは限らないのですね」

「そう。受信側では完了していても、返事だけが途中で消えることがあるの。送る側から見ると、成功か失敗かを確かめられない。だから、処理漏れを避けようとして再送するのよ」

澄江はホワイトボードを三つに分けた。左には Idempotency-Key、中央には request_id、右には trace_id と書いた。

「request_id は、一回のHTTPリクエストにつく番号。再送すれば、新しい番号になるわ」

「trace_id は、メールの読み取りから受注APIまで、いくつものサービスを通った道を追う番号ね」

「そう。そして Idempotency-Key は、同じ処理のお願いを見分ける受付番号。再送しても、最初の送信と同じものを使うの」

直人は、これまでミナがリトライのたびに新しい request_id を作っていたことを思い出した。番号は増えていたが、「同じ注文のお願い」という印は、どこにも残っていなかった。

澄江は、机の上の印刷物を直人へ渡した。API冪等性キーの開発者ガイドにも、クライアントがキーを作り、サーバーが最初の結果を保存する流れが示されている。

「受付番号は、処理をもう一度動かすための券ではないの。『同じお願いを、同じお願いとして見分ける札』よ」

次に澄江は、ホワイトボードへ小さな台帳の絵を描いた。行には、受付番号、リクエストの fingerprint、処理状態、初回レスポンス、作成時刻、更新時刻が並んだ。

「fingerprint は、注文内容を短い指紋にしたもの。商品や数量を正規化してから計算するの。同じ受付番号なのに指紋が違えば、誰かが番号を使い回していると分かるわ」

直人は注文データのJSONを二つ並べた。一つは商品、数量の順で、もう一つは数量、商品の順だった。見た目の順番は違っても、内容が同じなら同じ指紋になるよう、canonical JSON に整えてからハッシュを作ることにした。

「台帳には、結果のステータスコードとレスポンスボディも残します。二度目の依頼には、業務処理をせず、最初の結果をそのまま返すんですね」

「ええ。処理中なら二つ目を走らせず、処理が終わるまで待たせるか、処理中だと返す。同じ番号で内容が違うなら重複成功ではなく、入力不整合として 422 で拒否するの」

二人は、受注APIの入口を試作し始めた。ミナがメールから商品と数量を確定した時点で、クライアント側の処理が UUID v4 を一度だけ作り、HTTPヘッダーの Idempotency-Key に入れる形にした。

「大事なのは、リトライの中でUUIDを作らないこと。注文のお願いを作った直後に一つだけ発行して、その後の送信では同じ値を使うのよ」

最初のテストで、直人は小さくつまずいた。彼のコードでは、LangChainのリトライ処理が呼ばれるたびにキーを生成していたため、通信を切ると別の受付番号で注文がもう一度登録された。

「番号を作る場所が一段深すぎるね」

澄江の指摘で、直人はキーの生成をリトライ処理の外へ移した。ミナが一つの注文を受け取った時点でキーを保存し、送信関数にはそのキーを渡すだけにすると、再送でも番号は変わらなくなった。

次は保存先だった。二人はRedisに idem:{受付番号} という記録を置き、未登録なら処理状態を PROCESSING にする方針を決めた。処理が終われば、SUCCEEDED や FAILED と一緒にレスポンスのステータスコードと本文を保存し、作成時刻と更新時刻も記録する。

直人はRedisの存在確認と登録を別々に実行した。すると、同じキーのリクエストをほぼ同時に二つ送ったテストで、二人の作業員が同じ受付台へ走り込むように、どちらも「未登録」と判断した。

「確認してから登録するまでの隙間があるわ。ここを一つの受付にしないと、並列tool callでも二重に進んでしまう」

二人はRedisの原子的な登録を使い、最初の一件だけがロックを取れるように直した。後から来た依頼は、同じキーが PROCESSING なら注文処理へ進まず、保存された結果を待つ流れに変わった。

仕上げのテストでは、サーバーが注文を登録した直後に、直人が返事だけを遮断した。ミナはタイムアウトを受けて同じキーで再送したが、受注APIは台帳から最初のレスポンスを読み、注文処理をもう一度動かさずに返した。

「プロンプトに『必ず一度だけ実行して』と書くだけでは、ここは守れないのね」

「ロードバランサやライブラリの下で再送が起きるからね。だから受付側で受け止めるの。保存した台帳には期限も付けて、古い番号をいつまでも残さないようにするわ」

直人は最後に、ミナの画面から古い request_id と新しい request_id を追い、同じ Idempotency-Key に結びつくことを確認した。通信が揺れても、受付台だけは同じお願いを見失わなかった。

04

第4章 受付台を作る夜と、二人が同時に押したボタン

Redisと受付番号で注文を照合する受注センター

第4章 受付台を作る夜と、二人が同時に押したボタン - 本文

翌朝、ひだまり商事の受注センターでは、受付台が初めて本番の注文を受けた。画面の「送信中」はすぐに消え、注文は静かな青色の表示に変わった。昨日まで画面を見つめていた直人の肩から、少し力が抜けた。

「ミナ、今の受付番号は、もう一度送っても同じものを使えているね」

ミナは最初の注文を受けたとき、UUID v4で受付番号を作った。その番号をHTTPヘッダーのIdempotency-Keyに入れ、通信が切れても、自動リトライが起きても同じ番号を使った。request_idやtrace_idは一回ごとの通信を追う番号であり、再送される同じお願いを見分ける番号ではないことも、今では画面の横に小さく表示されている。

受付台は、番号だけを保存しなかった。注文内容を正規化したcanonical JSONからfingerprintを作り、番号と一緒にRedisへ置いた。保存に成功した処理だけが、在庫確認と注文登録へ進む仕組みだ。この流れは、受付番号と結果を保存し、同じ番号の再送には処理済みの結果を返すAPI設計として紹介されている。API冪等性キーの開発者ガイド

そのとき、ミナと別のエージェントが、同じ注文をほぼ同時に送った。二つの画面に同じ受付番号が現れたが、受付台は確認と確保を一つの操作として扱った。先に確保できた処理だけが在庫確認へ進み、もう一方は「処理中」として待った。

「検索してから登録するだけなら、二人とも空きを見つけてしまうんですね」

「そう。受付台は、見るだけの場所ではないよ。先に来た処理を、重ならない形で確保する場所なんだ」

処理が終わると、受付台には状態とレスポンスが保存された。状態は「処理中」「完了」「失敗」「内容不一致または拒否」に分かれた。同じ受付番号で同じ内容が再送されると、注文登録はもう一度行わず、保存済みのステータスコードとレスポンスボディを返す。同じ番号で内容だけが変わった場合は、fingerprintが合わず、受付は拒否された。この扱いは、同一キーの異なるペイロードをエラーにする設計にも沿っている。AIエージェント時代のIdempotency-Key設計

しかし、テスト画面の一つに「処理中」のまま残る注文が現れた。外部の在庫APIが途中で止まり、ミナは完了の返事を受け取れなかった。すぐに再実行すれば二重登録の恐れがあり、いつまでも待てば注文が止まる。

澄江は画面を見ながら、ゆっくり指を動かした。

「処理中の番号を、ただ消してはいけないよ。監査ログを見て、在庫APIが何を返したか、注文登録まで進んだかを確かめる。安全に続きから再開できるときだけ、再実行するんだ」

監査ログには、受付番号、エージェントID、セッションID、実行ユーザー、利用モデル、呼び出したAPI、DB操作、権限チェックの結果、レスポンス、エラー、処理時間が残った。ログを開けば、途中で止まった場所と、まだ実行していない処理が一本の道のようにつながって見えた。

ミナが注文登録や通知を呼び出す前には、ポリシーエンジンが許可と拒否を判定した。高い影響のある操作では、差分プレビューを表示し、人間の承認がなければ先へ進めない。注文内容に不自然な指示が混ざっていても、ミナの判断だけで送信されることはなかった。

テストでは、完了レスポンスが届かない場合、同じ番号で内容が変わる場合、複数のエージェントが同時に送る場合、外部APIが途中で止まる場合、承認が必要な処理を自動実行しようとする場合を順に試した。すべてが一度で通ったわけではない。それでも、受付台は失敗を「なかったこと」にせず、状態と記録を残し、次の判断を待てるようになった。

数日後、以前なら「送信中」の文字を囲んでいた机の上に、温かい湯気が立っていた。画面には、完了した注文と、確認を待つ注文が分かれて並んでいる。直人は同じ受付番号の再送履歴を開いたが、注文登録の記録は一つのままだった。

ミナも、すぐには送信しなかった。受付番号、内容、権限、状態を確かめてから、静かに次の仕事へ進んだ。直人の隣で澄江がうなずくと、受注センターには、急いで答えを出すときとは違う、落ち着いた空気が広がった。

05

第5章 同じ注文には、同じ返事が返る

受付番号で一件の注文を確認する受注センター

第5章 同じ注文には、同じ返事が返る - 本文

数日後の朝、受注センターでは、また受注APIへの通信が不安定になった。ミナが注文を送った直後、画面から返事が消え、「送信中」の文字だけが残った。

「直人さん、完了の返事が届きません。もう一度送ります」

「うん。でも、最初の受付番号は変えないで」

ミナは注文の内容を確かめた。商品名も数量も同じだった。そこで、最初の送信から持っていた Idempotency-Key をそのまま付けて、もう一度受注APIへ送った。

受注APIの受付台では、同じ番号の記録が見つかった。保存されていた注文内容の fingerprint、つまり内容を照らし合わせるための印も一致していた。受付台は注文登録をもう一度実行せず、最初の処理で保存していたステータスとレスポンスをミナへ返した。

画面に、静かな文字が浮かんだ。

「注文を受け付けました」

倉庫の春子が、出荷画面をのぞき込んだ。そこに並んでいたのは、同じ注文が二つではなく、一つだけだった。直人は画面を指さし、春子の隣で小さく息をついた。

「同じお願いなら、返事も同じになるんだね」

「そう。通信が切れても、同じ処理を別の注文にしないんだ」

受付番号が同じでも、送られた商品や数量が違えば、受付台は黙って通さない。たとえば数量が変わった再送には、不整合を知らせるエラーを返し、注文を止める。ミナはその注文を人の確認へ回し、勝手に新しい登録を作らなかった。

送信の前には、ポリシー判定も入っていた。通常の受注は許可されるが、注文の変更や削除のように影響が大きい操作は、差分を表示して人の承認を待つ。ミナが賢く見えることより、止まる場所がはっきりしていることを、直人は大切にしていた。

午後、直人は受付台の監査ログを開いた。そこには、最初に送ったエージェント、再送したエージェント、処理状態が「受付中」から「完了」へ変わった時刻、利用したAPI、権限チェックの結果、そして初回レスポンスまで残っていた。

「これなら、どこで立ち止まったかも追えるね」

「はい。返事がなくても、次の人が最初からやり直さずにすみます」

夕方、春子が出荷札を一枚だけ持ってきた。直人の画面には、もう「送信中」の文字はなかった。ミナは次の注文を読み取り、同じように受付番号を付けて、ゆっくりと受付台へ渡していた。

窓の外では、倉庫の明かりが一つずつ灯った。返事を待つ時間はまだなくならない。それでも、待っている間に同じ注文が増えないことを、みんなが知っていた。

06

第6章 静かな受付台と、夜に届く一通の再送

夜の受注センターでIdempotency-Keyを確認する直人

第6章 静かな受付台と、夜に届く一通の再送 - 本文

夜の受注センターでは、昼間のざわめきがすっかり消えていた。窓の外には、倉庫の明かりが細く続いている。画面の上では、受付台のランプだけが静かに点いていた。

直人は、ダッシュボードを開いていた。受付番号ごとに、処理状態と監査ログが並んでいる。注文の内容、実行した時刻、人の承認、ポリシー判定の結果まで、ひとつの流れで見えるようになっていた。

そのとき、ミナが新しい注文メールを受け取った。商品と数量を確かめ、注文APIへ送る。画面に「送信しました」と出るはずだったが、途中で小さな円が回り始めた。

「通信が途切れました。返事が届いていません」

直人は椅子から立ち上がりかけた。けれど、ミナの声には昼間のような迷いがなかった。注文のそばには、最初に作った Idempotency-Key が残っていた。

「新しい受付番号にはしません。同じ注文の続きなので、最初の番号を使います」

ミナは、同じ Idempotency-Key を付けてもう一度送った。通信ごとの request_id は新しくなったが、注文そのものに付けた受付番号は変わらない。直人は、画面の端で二つの通信が同じ番号につながるのを見ていた。

受付台は、届いた番号を静かに照合した。保存されていた番号を見つけると、注文の中身から作った fingerprint も確かめる。商品も数量も同じだったため、受付台は新しい注文を作らず、最初に保存したレスポンスをそのまま返した。

「受付済みです。初回の結果をお返しします」

返事は、夜の画面にすぐ現れた。倉庫の画面には、注文が一件だけ表示されている。春子は棚から商品を取り出し、伝票をそろえながら、いつもの落ち着いた声で言った。

「今夜も一件ね。これなら迷わず箱に入れられるわ」

直人は、監査ログの詳細を開いた。同じ受付番号の下に、最初の処理、通信の途切れ、再送、保存済みレスポンスの再利用、そしてポリシー判定の結果が一列に並んでいる。二つの通信があっても、倉庫へ渡された注文はひとつだった。

ミナは、ログの列をゆっくり見つめた。

「この番号は、私が何度話しかけても、同じお願いだと分かるのね」

「番号だけでなく、お願いの中身も一緒に見ているからだよ」

直人はそう答え、保存された fingerprint の欄を指で示した。もし同じ番号で別の商品や数量が届けば、同じお願いではないと受付台が知らせてくれる。ミナは小さくうなずき、処理済みの注文にそっと印を付けた。

窓の外で、倉庫のシャッターが低い音を立てた。夜の画面に「完了」と表示される。最後の受付台のランプが一つだけ消え、センターには、安心した機械の小さな待機音だけが残った。

関連キーワード

二重登録
通信タイムアウト
自動リトライ
Idempotency-Key
request_id
AIエージェント
受注API
Redis
fingerprint
二重処理防止

著者について

鈴木信弘(SNAMO)

鈴木信弘(SNAMO)- 静岡県を拠点に活動する総経験19年のフルスタックエンジニア。AI時代の次世代検索最適化技術「レリバンスエンジニアリング」の実装者として、GEO(Generative Engine Optimization)最適化システムを開発。2024年12月からSNAMO Portfolioの開発を開始し、特に2025年6月〜9月にGEO技術を集中実装。12,000文字級AI記事自動生成システム、ベクトル検索、Fragment ID最適化を実現。製造業での7年間の社内SE経験を通じて、受注システム自動化による業務時間の短縮や検品作業のデジタル化など、現場の課題を技術で解決してきた。富山大学工学部卒、基本情報技術者保有。

プロフィールを見る

よくある質問

Q1Idempotency-Keyとは何ですか?
同じリクエストの再送を見分けるための識別子です。同じ注文を再送するときに同じIdempotency-Keyを付けることで、受注APIは二重登録せず、最初の処理結果を再利用できます。
Q2request_idやtrace_idとIdempotency-Keyは何が違いますか?
request_idやtrace_idは、リクエストや処理の追跡を目的とした識別子です。一方、Idempotency-Keyは「同じ処理の再送かどうか」を判定し、二重処理を防ぐために使います。再送のたびにrequest_idが変わっても、同じ注文には同じIdempotency-Keyを使用します。
Q3通信タイムアウトが起きたとき、なぜ二重登録が発生するのですか?
クライアント側では応答を受け取れなくても、サーバー側では注文処理が完了している場合があります。その状態で自動リトライを行うと、同じ注文が新規注文として再度処理され、二重登録につながります。
Q4Idempotency-Keyにはどのような値を使えばよいですか?
ほかの注文と重複しない値を使います。記事では、受付番号としてUUID v4を利用しています。重要なのは、同じ注文の再送には同じキーを使い、新しい注文には新しいキーを発行することです。
Q5Idempotency-Keyを使うと、どのように二重登録を防げますか?
受注APIがIdempotency-Keyを確認し、初回処理時に注文の指紋や処理結果を保存します。同じキーで再送された場合は、注文を新規登録せず、保存済みの結果を返します。これにより、通信障害後のリトライでも処理を一度に保てます。
Q6Idempotency-Keyの情報はどこに保存しますか?
記事ではRedisにIdempotency-Key、注文内容の指紋、処理状態、処理結果などを保存しています。これにより、再送時の照合や結果の再利用を高速に行えます。実際の運用では、保存期間や期限切れの扱いも設計します。
Q7同時送信や並列実行が起きても二重処理を防げますか?
Idempotency-Keyの登録や状態更新を原子的に行う仕組みを用意すれば、防止できます。複数のリクエストが同時に届いた場合も、最初の処理だけを実行し、後続のリクエストには処理中または保存済みの結果を返します。状態管理や監査ログ、人による承認を組み合わせることも重要です。