メインコンテンツまでスキップ

障害と再試行の処理

Audience

このAPIは、Roktネットワーク上で構築する統合パートナー向けです。Roktのeコマースパートナーで独自のチェックアウトに配置を統合する場合は、代わりにRokt Ecommerce開発者ドキュメントを使用してください。

Partnerships APIは再試行の安全性を考慮して構築されています。3つのプリミティブが契約を担っています:

  • Idempotency-Key(送信するリクエストヘッダー):再試行を単一のサーバー側操作にまとめます。すべての書き込みに必須です。サーバーは24時間応答をキャッシュし、その後キーは期限切れになります。
  • X-Operation-Id(サーバーが返す応答ヘッダー):操作記録への耐久性のあるハンドルです。ネットワーク障害から復旧するためにGET /v1/partnership/operations/{operation_id}と共に使用します。
  • request_id(すべての応答エンベロープのフィールド;X-Request-Id応答ヘッダーでも返されます):単一試行のトレースIDです。チケットを提出する際にサポートにこれを渡します。
注記

すべての応答はラップされています。 成功とエラーの応答は両方とも{ status, error, message, request_id, data }として返されます。以下の例は、request_iderrorを検査する再試行ロジックがサーバーが実際に出力するものと一致するように、完全なエンベロープを示しています。

正しく使用すれば、再試行は無料です。

障害シナリオ1: 応答前のネットワークタイムアウト障害シナリオ1: 応答前のネットワークタイムアウト への直接リンク

リクエストを送信しましたが、応答を受け取る前に接続が切れました。サーバーが変更をコミットしたかどうかは不明です。

解決策:

  1. 部分的な応答からX-Operation-Idを取得した場合、操作を直接ポーリングします:

    curl https://accounts.rokt.com/v1/partnership/operations/$OPERATION_ID \
    -H "Authorization: Bearer $TOKEN" \
    -H "X-Platform-Parent-Account-Id: $PARENT"

    data.statuspending / in_progress / completed / failedのいずれかです。completedの場合、data.response_bodyは元の書き込みの応答ペイロードを持ちます。failedの場合、data.errorは最後にキャプチャされたエラーメッセージです。

  2. X-Operation-Idがない場合、**同じIdempotency-Key**で元の呼び出しを再試行します。24時間の重複排除ウィンドウ内で、元の操作が成功した場合はサーバーがキャッシュされた応答を返し、失敗した場合は再実行します。

障害シナリオ2: Roktからの5xx障害シナリオ2: Roktからの5xx への直接リンク

サーバー側の一時的なエラーです。待機して再試行し、同じキーを使用します。

curl -X PUT https://accounts.rokt.com/v1/partnership/accounts/<your-account-id>/status \
-H "Authorization: Bearer $TOKEN" \
-H "X-Platform-Parent-Account-Id: $PARENT" \
-H "Idempotency-Key: $SAME_KEY_AS_BEFORE" \
-H "Content-Type: application/json" \
-d '{ "status": "active" }'

指数バックオフで3回再試行してもまだ5xxが続く場合は、各試行からrequest_idをキャプチャし、サポートチケットを提出します。繰り返し叩かず、バックオフしてエスカレーションします。

障害シナリオ3: 400バリデーションエラー障害シナリオ3: 400バリデーションエラー への直接リンク

ペイロードが間違っています。エンベロープのmessageフィールドが問題のあるパラメータを説明し、request_idがトレースIDです。

{
"status": 400,
"error": "BadRequest",
"message": "no partnership vertical mapping for partnerVerticalId=1500 partnerSubVerticalId=9999",
"request_id": "0e3a1b9c-1234-4abc-9def-aaaabbbbcccc",
"data": null
}

ペイロードを修正し、**新しいIdempotency-Key**で再送信します。古いキーは失敗した操作としてキャッシュされており、24時間ウィンドウ内で再利用するとキャッシュされた400が返されます。

障害シナリオ4: 401 / 403 / 422障害シナリオ4: 401 / 403 / 422 への直接リンク

401 Unauthorized: APIトークンが欠落しているか、形式が不正か、期限切れです。トークン発行統合を通じてトークンを更新し、再試行します。Authenticationを参照してください。

403 Forbidden: APIトークンは有効ですが、このアカウントに対するマネージャー管理関係の権限がありません、またはX-Platform-Parent-Account-Idが管理アカウントの実際の親と一致しません。以下のいずれかです:

  • 関係が取り消された(Rokt側でプラットフォームからマーチャントがオフボードされた)。
  • アカウントが別のパートナープラットフォームに属している。
  • 間違ったX-Platform-Parent-Account-Id値を送信した。

これを運用チームに報告します。再試行しないでください。403は構造的なものであり、一時的なものではありません。

422 Unprocessable: 必要なヘッダーが欠落しています。最も一般的には、書き込み呼び出しでのX-Platform-Parent-Account-Idヘッダーです。ヘッダーを追加して再試行します。

curl -X PUT https://accounts.rokt.com/v1/partnership/accounts/<your-account-id>/status \
-H "Authorization: Bearer $NEW_API_TOKEN" \
-H "X-Platform-Parent-Account-Id: $PARENT" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{ "status": "active" }'

失敗シナリオ5: 409コンフリクト失敗シナリオ5: 409コンフリクト への直接リンク

2つの異なる意味:

register/partnershipで: 別のパートナープラットフォームがすでにこのstore_identifierを所有しています。商人のストアフロントURLは、別のプラットフォームを通じて最初に登録されました。

{
"status": 409,
"error": "Conflict",
"message": "Rokt Account already exists",
"request_id": "0e3a1b9c-...",
"data": null
}

このプロンプトを商人にそのまま表示してください:

アカウント作成に問題があり、さらなる確認が必要です。パートナープラットフォームサポートにメールしてください。

登録を再試行しないでください。クロスパートナーの解決手順は手動です。

書き込みエンドポイント(コントロール、ステータス)で: 進行中の操作と異なるリクエストボディでIdempotency-Keyを再利用しました。以下のいずれかを行ってください:

  • 少し待って再試行してください。一部のパスは非同期で処理されます。
  • 新しいIdempotency-Keyを生成して再試行してください。これにより新しい操作が開始されます。

失敗シナリオ6: in_progressで操作が停滞failure-scenario-6-operation-stuck-in-in_progress への直接リンク

書き込みが202 Accepted(または同期的に完了)を返し、X-Operation-Idを提供しました。GET /v1/partnership/operations/{operation_id}をポーリングし、data.statusがそのエンドポイントで予想されるレイテンシーを超えてもin_progressのままです(例: ステータス/コントロールで60秒以上、登録で5分以上)。操作はcompletedにもfailedにも達していません。

検出方法:

  • data.status === "in_progress"が長期間にわたってすべてのポーリングで確認される。
  • 連続したポーリングでdata.updated_atに動きがない。操作レコードが触れられていない。
  • data.attempts(存在する場合)が増加していない。非同期ワーカーがそれを拾っていない。
{
"status": 200,
"error": null,
"message": "ok",
"request_id": "0e3a1b9c-...",
"data": {
"operation_id": "op_3a1b9c...",
"status": "in_progress",
"updated_at": "2026-05-20T19:14:00Z",
"response_body": null,
"error": null
}
}

解決策: エスカレーションし、元の書き込みを再試行しないでください。 サポートチケットを以下の情報で提出してください:

  • 停滞しているX-Operation-Id
  • 送信したIdempotency-Key
  • 書き込みレスポンスからの元のrequest_id
  • エンドポイントとサニタイズされたペイロード。

再試行が危険な理由。 停滞しているin_progress操作はほぼ確実に部分的にコミットされた状態を持っています: 少なくとも1つのプロビジョニングステップが実行され、ワーカーがクラッシュ、停止、または下流リソースで詰まっています。新しいIdempotency-Keyで元の書き込みを再送信すると、最初の操作と競合する2番目の操作が作成されます。エンドポイントによっては以下のような結果を生む可能性があります:

  • 重複登録(元のコミットが成功したが、ポストコミットのプロジェクションが失敗した場合)。
  • マーケットプレイスコントロールの状態が競合する。
  • 進行中のステータスと競合し、mixed状態に残る。
  • 同じ商人に対する2番目のStripe Connectセッション。

同じIdempotency-Keyで再送信しても役に立ちません: キーはすでに停滞している操作にバインドされており、サーバーは「操作進行中」(409)にショートサーキットします。唯一の安全な行動はエスカレーションです: サポートは既存の操作を再開するか、failedとしてクリーンにマークして、既知の状態から再試行できるようにするためのランブックを持っています。

ジッター付き指数バックオフ: 最大5回の試行
  • 試行1: 即時
  • 試行2: 1秒待機 ± ジッター
  • 試行3: 2秒待機 ± ジッター
  • 試行4: 4秒待機 ± ジッター
  • 試行5: 8秒待機 ± ジッター
  • 試行5の後に諦め、すべてのrequest_idを持ってサポートにエスカレーション
import time, random, requests

def put_with_retry(url, body, token, parent, idem_key, max_attempts=5):
for attempt in range(max_attempts):
r = requests.put(
url,
headers={
"Authorization": f"Bearer {token}",
"X-Platform-Parent-Account-Id": parent,
"Idempotency-Key": idem_key, # same key across retries
"Content-Type": "application/json",
},
json=body,
)
if r.status_code < 500 and r.status_code != 408:
return r # success, 4xx (don't retry), or done
time.sleep((2 ** attempt) + random.random())
raise RuntimeError(
f"exhausted retries; last request_id={r.json().get('request_id')}"
)
指針
  • 同じ論理操作の再試行では常にIdempotency-Keyを再利用 24時間の重複排除ウィンドウ内で。サーバーにそれらを統合させます。
  • 400の後は常に新しいIdempotency-Keyを生成。 古いキーは残りの24時間ウィンドウで無効です。
  • 試行ごとにrequest_idを常にログに記録。 これはサポートが必要とするトレースIDです。
  • 401/403を再試行しない。 それらは構造的な失敗です。
  • 422は必須ヘッダーを忘れたことを意味します。 追加して、同じキーで再試行してください。
  • register/partnershipで409を再試行しない。 商人に表示してください。
  • タイムアウトの場合、ヘッダーをキャプチャした場合は盲目的な再試行よりもX-Operation-Idのポーリングを優先 それは安価で元の結果を浮き彫りにします。
この記事は役に立ちましたか?