午後、ある小売店のバックオフィスで電話が鳴った。「さっき注文したのに、確認メールが2通来ています。しかもカード明細を見たら同じ金額が2回引き落とされていました」。お客様は昼休みにスマートフォンから注文を確定させようとしたが、店舗の回線が混み合っていたのか画面がなかなか切り替わらない。焦って「注文する」ボタンをもう一度押した。実は最初のリクエストはサーバーに届いていて、静かに処理が進んでいた。そこにもう一度同じ注文が重なり、在庫が二重に引き当てられ、決済も二重に走ってしまった。担当者はお客様への謝罪と返金対応に追われ、倉庫では出荷担当が「同じ注文が2件ある、どちらが本物か」と混乱する。こうした光景は、実は特別なシステムトラブルではなく、多くの受発注システムや予約システムで日常的に起こりうる構造的な問題だ。

二重注文・二重請求はなぜ「よくある」トラブルなのか

この手のトラブルが起きると、多くの発注者は「システムのバグでは」と考える。しかし実際には、バグというより設計上の考慮漏れであることがほとんどだ。ネットワークが一瞬途切れる、通信が遅い、サーバーが混雑している。こうした状況は程度の差こそあれ、どんなシステムでも避けられない。問題は、そうした不安定な状況下で同じ処理が複数回届いたときに、システム側がそれをどう扱うかという設計にある。ここを事前に取り決めていないシステムは、規模が大きくなるほど、あるいは利用者が増えるほど、二重処理のリスクにさらされていく。

なぜ二重処理が起きるのか、3つの理由

まず1つ目は、通信の遅延によってユーザー自身が再送信してしまうケースだ。冒頭の例のように、注文ボタンを押した後の反応が遅いと、人はつい「うまく送信できていないのでは」と不安になり、もう一度ボタンを押してしまう。これは利用者の落ち度ではなく、待たされる画面設計や通信環境の問題である。

2つ目は、システム側が自動でリトライする仕組みによるものだ。決済代行会社との通信やクラウドサービス間の連携では、一時的な通信エラーが起きた際に、システムが「失敗したのでもう一度送ろう」と自動で再送する設計が一般的になっている。この仕組み自体は信頼性を高めるための正しい工夫だが、最初のリクエストが実はサーバー側で処理済みだった場合、結果として同じ処理が二重に実行されてしまう。

3つ目は、そもそも同じ処理が複数回届くこと自体を完全には避けられない場面があるという事実だ。インターネットを介した通信では、途中の経路で遅延や重複が発生することがあり、どれだけ通信環境を整えても、受け取る側で「これは本当に一度だけの処理か」を確認する仕組みがなければ、確実性は保証できない。つまり二重処理は、送る側の努力だけでは防ぎきれず、受け取る側の設計で吸収する必要がある問題なのだ。

放置するとどうなるか

この問題を「たまに起きる例外」として放置すると、じわじわと事業の信頼を蝕んでいく。まず直接的なダメージとして、二重請求によるお客様からのクレームが発生する。カード明細に身に覚えのない重複請求があれば、お客様は不安と不信感を抱き、返金対応の手間だけでなく、ブランドへの信頼そのものを損なう。次に業務面では、在庫の二重引き当てが起きる。同じ商品が2件の注文で確保されてしまうと、本当に必要としている別のお客様に販売できなくなったり、出荷担当者が手作業で注文の重複を見抜いて取り消す羽目になったりする。こうした人力の後始末は、注文件数が増えるほど現場の負担として重くのしかかり、ミスの温床にもなっていく。

冪等性とは何か、何を解決するのか

この問題を根本から解決する考え方が「冪等性(べき等性)」と呼ばれる設計原則だ。難しい言葉に聞こえるが、意味はいたってシンプルで「同じ操作を何度行っても、結果が1回分と同じになる」という考え方を指す。身近な例で言えば、エレベーターの行き先ボタンだ。5階のボタンを1回押しても3回連打しても、エレベーターが向かう先は5階のままで変わらない。ボタンを押すという操作を何度繰り返しても、起きる結果は常に1つに保たれている。これと同じ性質を、注文や決済の処理にも持たせようというのが冪等性の考え方である。

一意の識別子で重複を検知する

具体的な仕組みの1つが、注文ごとに一意の識別子(注文番号やリクエスト番号のようなもの)を発行し、その番号をもとに「これは既に受け取った注文かどうか」をシステムが判定する方法だ。お客様が同じ注文ボタンを2回押しても、送信される識別子が同じであれば、システムは「これは新しい注文ではなく、さっき受け取ったものと同一だ」と認識し、2件目を処理せずに済ませることができる。

処理済みかどうかを確認してから実行する

もう1つの仕組みは、実際の処理(在庫を減らす、決済を確定させるなど)を実行する直前に、必ず「この注文は処理済みか」を確認するステップを設けることだ。人間で言えば、伝票にハンコを押す前に「これ、もう処理した伝票じゃないか」と一度確認するようなものだ。この一手間があるだけで、通信の乱れや自動リトライによって同じ指示が複数回届いても、実際に実行されるのは1回だけに保たれる。

結果として何が変わるのか

冪等性が設計に組み込まれたシステムでは、お客様が不安になってボタンを連打しても、通信環境が多少不安定でも、最終的にシステムに残る結果は常に「注文1件、決済1回」に収束する。これはお客様の安心感だけでなく、現場担当者が重複対応に追われる時間そのものをなくす効果を持つ。

発注時に確認すべきポイント

システム開発を発注する立場として、専門的な実装方法まで理解する必要はない。ただし、次のような問いを開発会社に投げかけておくことは、後々のトラブルを大きく減らす。「注文ボタンを連打したり、通信が不安定な状態で同じ操作を繰り返したりした場合、システムはどう振る舞いますか」という質問は、その1つだ。あわせて「決済処理でエラーが起きて自動的に再送されるとき、二重に請求されないような仕組みはありますか」と尋ねてみるとよい。もし担当者から「そこは想定していません」「まだ検討していません」という答えが返ってきたら、それは要件として明確に伝えるべきタイミングだと考えてほしい。冪等性という言葉を使わなくても、「同じ操作を繰り返しても結果は1回分にしてほしい」と伝えるだけで、開発側には十分に意図が伝わる。

現実的な進め方

既に稼働しているシステムをすべて作り直す必要はない。まずは、二重処理が起きた際に実際にどれくらいの影響が出ているか、クレーム件数や在庫のズレを振り返るところから始めるとよい。その上で、注文や決済など金銭や在庫に直結する処理を優先的に見直し、識別子による重複検知や処理済み確認の仕組みを段階的に組み込んでいく。すべてを一度に完璧にしようとせず、影響の大きい箇所から着実に手当てしていくことが、現場の負担を増やさずに信頼性を高める現実的な道筋になる。

壁を越えて働く人たちへ

通信が途切れても、システムが混み合っていても、お客様は今日も注文ボタンを押してくれる。その一押しに応えるのは、目立たない裏側の設計であり、それを支えているのは「もう一度確かめよう」と地道に手を動かす人たちだ。二重注文や二重請求という小さなほころびを見過ごさず、仕組みとして越えていく。その積み重ねこそが、お客様の信頼という、何よりも壊れやすく、何よりも価値のあるものを守っている。壁を越えて働く人たちの仕事は、こうして誰の目にも留まらない場所で、確かに世界を支えている。