← トピック

API プロバイダーとのウォレット送金:リクエストキューを詰まらせない

プラットフォームと API プロバイダーの間で連鎖する送金呼び出しがリクエストキューをあふれさせる仕組みと、キュー・即時応答・結果のプッシュでプロバイダーが遅くてもプラットフォームを安定させる方法。

プラットフォームはユーザーのウォレットを預かり、API プロバイダーはプラットフォームが提供するサービスの裏側でサーバーを運用しています。ユーザーがあるプロバイダーのサービスを使う前に資金はプラットフォームからプロバイダーへ移り、使い終わると戻ってきます。多くの連携では、この送金を双方向に連鎖する同期 HTTP 呼び出しで作っています。負荷が上がるとこの連鎖が両側のリクエストキューを埋め、遅いプロバイダーが一つあるだけでプラットフォーム全体が巻き込まれます。プラットフォームの安定性が、他社のサーバーに左右されるべきではありません。

送金はリクエストの連鎖になっている

ユーザープラットフォームAPI プロバイダーサービスを開始プラットフォームの worker が待つPOST /transfer-inプロバイダーを待つGET /wallet/verifyプロバイダーの worker も待つ200 OK200またはタイムアウトで状態不明GET /transfer/123完了まで 2 秒ごと開始できます
変更前:1 回の送金を HTTP 呼び出しの連鎖で行う

プラットフォームの worker は、プロバイダーからのコールバックも含めた往復の間ずっと占有されます。プロバイダーの worker は、そのコールバックを待つ間占有されます。お互いがお互いを待つので、トラフィックが増えると両方のプールが同時に埋まります。タイムアウトすると送金の状態がわからなくなり、状態のポーリングと再試行が始まります。冪等キーがなければ、再試行で二重に送金されることもあります。

遅いプロバイダー一つが全体の問題になるまで

キャンペーン開始送金が増える
プロバイダー C が遅くなる150 ms → 5 秒
プラットフォームの worker が占有C を待っている
共有プールを使い切るすべてのリクエストが待ち行列へ
リクエストがタイムアウト
再試行と状態のポーリングリクエストがさらに増える
ログイン、入金、ほかのプロバイダーが失敗C とは無関係
一時的な遅れがリクエストの洪水になる

ベンチマークではなく試算の例です(2026-11-09 作成)。毎秒 500 件の送金が 3 つのプロバイダーに分かれ、プラットフォームのプールは 200 worker です。使われる worker 数はリトルの法則で出せます。毎秒の送金数 × 1 件が worker を占有する秒数です。

変更後:すぐ受け付け、裏で処理し、結果をプッシュする

ユーザープラットフォームAPI プロバイダーHibiraサービスを開始処理中台帳に記録、worker を解放POST /transfers冪等キー、キューから送信202 Accepted記録済み、worker を解放プロバイダーは自分のキューから自分のペースで処理するtransfer.settledprivate-partner-acmetransfer.settledid 123、金額balance.updatedprivate-wallet-42balance.updated
変更後:どちらもすぐ応答し、結果はイベントで届く
  1. プラットフォームはまずユーザーに応答する。 送金を処理中として台帳に書き、キューに入れてから応答します。ユーザーの画面には「処理中」と表示され、イベントが届くと自動で更新されます。
  2. ディスパッチャーが各プロバイダーへ送金を送る。 冪等キー、短いタイムアウト、プロバイダーごとに決まった枠数を付けます。プロバイダーは送金を記録した時点で 202 を返すので、同じキーでの再試行は常に安全です。
  3. コールバックしない。 リクエストにはプロバイダーが必要とするものをすべて署名付きで載せるので、プロバイダーが確認のためにプラットフォームを呼び返す必要はありません。
  4. 結果はプッシュで。 プロバイダーはそのプラットフォーム用のプライベートチャンネル、たとえば private-partner-acme に transfer.settled を発行します。プラットフォームのバックエンドは WebSocket 接続を一つ保ち、プロバイダーの認可エンドポイントの署名で購読します。台帳を更新し、ユーザーのウォレットチャンネルに balance.updated を発行します。プロダクト間の残高同期と同じやり方です。
  5. 取りこぼしは一度の確認で。 プラットフォームは数分ごとに、各プロバイダーへまだ処理中の送金をまとめて一度だけ問い合わせます。送金ごとのポーリングはしません。

プロバイダーが不安定でもプラットフォームは安定させる

  • プロバイダーごとに枠を分ける。 遅くなったプロバイダーが埋めるのは、ディスパッチャーの自分の枠だけです。ログイン、入金、ほかのプロバイダーの worker はそのまま残ります。
  • 応答しないプロバイダーには送るのをやめる。 タイムアウトが続いたらそのプロバイダーのキューを止め、サービスを一時的に利用不可と表示し、少し待ってから再開します。送金は占有された接続ではなく、台帳の中で処理中として待ちます。
  • WebSocket が切れても何も止まらない。 送金は受け付け続けます。接続が戻れば、まとめた確認でその間の分が処理されます。
  • ユーザーがプロバイダーの応答時間を待つことはない。 画面はプラットフォーム自身の速さで応答し、結果は用意でき次第表示されます。

よくある質問

遅い API プロバイダーが、なぜプラットフォーム全体を遅くするのですか?

プラットフォームの worker がそのプロバイダーを待っているからです。同期呼び出しはプロバイダーが応答するまで worker を一つ占有し、その worker はほかのすべての機能と共有されています。一つのプロバイダーが遅くなると worker が尽き、そのプロバイダーとは関係のないリクエストまで後ろに並びます。

WebSocket が送金 API の代わりになるのですか?

いいえ。送金そのものは冪等キー付きの HTTP リクエストのままで、双方の台帳に記録されます。WebSocket が置き換えるのは待つ部分、つまり占有された接続、状態のポーリング、コールバックです。結果はイベントとして届きます。

送金が完了したときにプラットフォームが切断されていたら?

何も失われません。双方の台帳にすでに送金が記録されているからです。pusher-js などのクライアントライブラリは自動で再接続し、処理中の送金をまとめて確認すれば取りこぼしも処理されます。適用済みのイベントは送金 ID で無視します。

接続はいくつ必要ですか?

プラットフォームのバックエンドから各プロバイダーのチャンネルへ WebSocket 接続が一つあれば、そのプロバイダーとのすべての送金をまかなえます。ユーザー数は関係ありません。Hibira では 1 回の発行が 1 メッセージで、有料プランでは購読者への配信を数えません。料金をご覧ください。

製品名は各所有者の商標です。