GH GambleHub

Webhookとイベントのidempotency

TL;DR(ドクター)

良いWebhookは署名された(HMAC/mTLS)で、受信者に指数関数的なバックアップと重複除外を持つ、少なくとも1回のモデルで配信される、要約された、idempotentイベントです。エンベロープ('event_id'、 'type'、 'ts'、 'version'、 'attempt'、' signature')、タイムウィンドウ(≤ 5分)、レスポンスコード、リトレイ、DLQ、ステータスエンドポイントに同意します。


1)役割と配達モデル

送信者(you/provider):イベント、サインを生成し、最大2xxを配信しようとします。3xx/4xx/5xx(明示的に「受け入れない」を除く)で再試行し、DLQをリードし、リプレイAPIを提供します。
受信者(パートナー/サービス):署名/タイムウィンドウをチェックし、dedupとidempotent処理を行い、正しいコードで応答し、/status と/ack replayを'event_id'で提供します。

保証:少なくとも一度。受信者は、重複と並べ替えを処理できる必要があります。


2)イベントの封筒

json
{
"event_id": "01HF7H9J9Q3E7DYT5Y6K3ZFD6M",
"type": "payout.processed",
"version": "2025-01-01",
"ts": "2025-11-03T12:34:56.789Z",
"attempt": 1,
"producer": "payments",
"tenant": "acme",
"data": {
"payout_id": "p_123",
"status": "processed",
"amount_minor": 10000,
"currency": "EUR"
}
}

必須フィールドは'event_id'、 'type'、 'version'、 'ts'、 'attempt'です。
進化のルール:フィールドの追加;delete/change types-新しい'バージョン'でのみ。


3)セキュリティ: 署名とバインディング

3.1 HMAC署名(デフォルト推奨)

タイトル:

X-Signature: v1=base64(hmac_sha256(<secret>, <canonical>))
X-Timestamp: 2025-11-03T12:34:56Z
X-Event-Id: 01HF7...
正規文字列:

<timestamp>\n<method>\n<path>\n<sha256(body)>
受信者に確認してください:
  • abs(現在 'X-Timestamp') 300s
  • 'X-Event-Id'は前に処理されない(dedup)
  • 'X-Signature'マッチ(時間安全比較)

3.2追加。対策

非常に敏感なwebhookのためのmTLS。
IP/ASN allow-list。
Webhookがコールバックを開始する場合、送信者制約のためのDPoP(オプション)。


4) Idempotencyと重複除外

4.1イベントのidempotency

同じ'event_id'を持つイベントは、再度ステートを変更してはいけません。受信者:
  • TTL ≥ 24-72時間のidempotentキャッシュ(KV/Redis/DB)に「event_id」を格納します。
  • 再リターンの処理結果(成功/エラー、アーティファクト)を保存します。

4.2コマンドidempotency(コールバック)

WebhookがクライアントにAPIをプルさせた場合(例:「confirm payout」)、 RESTコールで'Idempotency-Key'を使用して、結果をサービス側に保存します(正確に一度の結果)。

KVモデル(最低):

key: idempotency:event:01HF7...
val: { status: "ok", processed_at: "...", handler_version: "..." }
TTL: 3d

5)レトライとバックオフ

推奨プロット(ジッタ付き指数):
  • '5s、 15s、 30s、 1m、 2m、 5m、 10m、 30m、 1h、 6h、 12h、 24h'(その後、毎日N日まで)
コードソリューション:
  • 2xx-成功、リトレイを停止します。
4xx:
  • '400/ 401/403/404/422'-署名/フォーマットがok(クライアントエラー)の場合は再送できません。
  • '429'-retrayim by 'Retry-After'またはバックオフ。
  • 5xx/network-retrayim。

送信ヘッダ:'User-Agent'、 'X-Webhook-Producer'、 'X-Attempt'。


6)受信機側処理

疑似パイプライン:
pseudo verify_signature()
if abs(now - X-Timestamp) > 300s: return 401

if seen(event_id):
return 200 // идемпотентный ответ

begin transaction if seen(event_id): commit; return 200 handle(data)       // доменная логика mark_seen(event_id)    // запись в KV/DB commit return 200

Transactionality: 「seen」ラベルは、失敗時の二重処理を避けるために、操作の効果(または結果を修正した後)でアトミックに設定する必要があります。


7)順序およびスナップショットの保証

注文は保証されていません。'data'の't'とドメイン'seq'/'version'を使用して関連性を検証します。
長いlags/lossの場合は、送信者でadd/replay、受信者で/resyncを実行します(/IDウィンドウでスナップショットとデルタを取得します)。


8)状態、再生およびDLQ

8.1送信者エンドポイント

'POST/webhooks/replay'-'event_id'リストまたはタイムウィンドウで。
'GET/webhooks/events/: id'-ソースパッケージと試行履歴を表示します。
DLQ: 「dead」イベント(リトレイ制限が使い果たされました)→別々のストレージ、アラート。

8.2受信者エンドポイント

'GET/ webhooks/status/:event_id'-'seen=true/false'、'processed_at'、'handler_version'。
'POST/webhooks/ack'-(オプション)DLQからの手動処理の確認。


9)エラー契約(受信機の応答)

http
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
Retry-After: 120
X-Trace-Id: 4e3f...

{
"error": "invalid_state",
"error_description": "payout not found",
"trace_id": "4e3f..."
}

推奨事項:常に明確なコードを返し、可能であれば'Retry-After'を返します。詳細なセキュリティ情報は返さないでください。


10)監視およびSLO

メトリック(送信者):
  • 配信p50/p95、成功率、リトレイ/イベント、ドロップレートDLQ、シェア2xx/4xx/5xx、ディレイウィンドウ2xxまで。
メトリック(受信者):
  • fail rate (signature/time)、 dup-rate、 latency handler p95、 5xxを確認します。
SLOベンチマーク:
  • 配達:≥ 99。イベントの9%は2xx <3 c p95を受け取ります(最初の成功した試みの後)。
  • 暗号検証:署名検証≤ 2-5 ms p95。
  • Dedup: 0の繰り返しエフェクト(ドメインレベルで正確に1回の結果)。

11)データセキュリティとプライバシー

Webhookの本体にPAN/PIIを送信しないでください。IDを使用してから、承認されたAPIに対して詳細をプルします。
ログの機密フィールドをマスクします。TTLでイベントボディを最小限に保存します。
DLQの保存と再生を暗号化します。


12)バージョン管理と互換性

'version' (envelope)およびtransit: '/webhooks/v1/payments'のバージョン。
新しいフィールドはオプションです。削除-'Sunset'期間の後のみ。
機械読み取り可能な変更履歴(自動チェック用)の変更を文書化します。


13)テストケース(UATチェックリスト)

  • 同じ'event_id'→1つのエフェクトと'200'を重複させる。
  • 署名:正しいキー、間違ったキー、古いキー(回転)、'X-Timestamp'ウィンドウの外。
  • バックオフ:受信者は'429'に'Retry-After'→正しい一時停止を与えます。
  • 注文:イベント'……処理された'前に来る'……created'→正しい処理/待ち。
  • エフェクトと'mark_seen'→atomicity/repeatの間のレシーバでのデータベース障害。
  • DLQおよび手動リプレイ→成功した配達。
  • 大量の「嵐」(プロバイダがパックを送信)→損失なし、制限はクリティカルを抑制しません。

14)ミニスニペット

送信者署名(擬似):
pseudo body = json(event)
canonical = ts + "\n" + "POST" + "\n" + path + "\n" + sha256(body)
sig = base64(hmac_sha256(secret, canonical))
headers = {"X-Timestamp": ts, "X-Event-Id": event.event_id, "X-Signature": "v1="+sig}
POST(url, body, headers)
チェックと宛先(擬似):
pseudo assert abs(now - X-Timestamp) <= 300 assert timingSafeEqual(hmac(secret, canonical), sig)

if kv.exists("idemp:"+event_id): return 200

begin tx if kv.exists("idemp:"+event_id): commit; return 200 handle(event.data)        // доменная логика kv.set("idemp:"+event_id, "ok", ttl=259200)
commit return 200

15)頻繁なエラー

重複排除→繰り返し効果なし(二重リファンド/ペイアウト)。
タイムスタンプ/ウィンドウのない署名→リプレイの脆弱性。
すべてのパートナーに1つのHMACシークレットを格納します。
Responses '200'クラッシュイベントの結果→損失を修正する前に。
セキュリティの詳細を回答/ログに「洗い流す」。
DLQ/リプレイの欠如-インシデントは解決できません。


16)実装チートシート

セキュリティ:HMAC v1+'X-Timestamp'+'X-Event-Id'、ウィンドウ≤ 5分;必要に応じてmTLS/IP allow-list。
'event_id'、 'type'、 'version'、 'ts'、 'attempt'、' data'。
配信:最低1回、ジッタ付きバックオフ、'Retry-After'、 DLQ+リプレイAPI。
Idempotency: KV-cache 24-72 h、エフェクト+'mark_seen'の原子固定。
観測可能性:配信、署名、重複した指標;trace_idを指定します。
ドキュメント:バージョン、レスポンスコード、例、UATチェックリスト。


履歴書のサマリー

永続的なWebhookは、3つのクジラに基づいて構築されています。署名付きの封筒、少なくとも1回の配達、およびidempotent処理です。コントラクトを正式化し、HMAC/mTLSとタイムウィンドウを有効にし、retrai+DLQを実装してリプレイし、idempotentラベルを保存し、エフェクトをアトミックにキャプチャします。その後、ネットワーク障害、ロードピーク、まれな「運命の重複」でも、イベントは信頼性が維持されます。

Contact

お問い合わせ

ご質問やサポートが必要な場合はお気軽にご連絡ください。いつでもお手伝いします!

統合を開始

Email は 必須。Telegram または WhatsApp は 任意

お名前 任意
Email 任意
件名 任意
メッセージ 任意
Telegram 任意
@
Telegram を入力いただいた場合、Email に加えてそちらにもご連絡します。
WhatsApp 任意
形式:+国番号と電話番号(例:+81XXXXXXXXX)。

ボタンを押すことで、データ処理に同意したものとみなされます。