Webhooks:重播和握手
1)基本交付模式
At-least-once(默認):事件將傳送≥1次。保修是通過接收器的等效性實現的。
握手(ACK):只有來自收件人的任何2xx(通常為200/204)表示成功。其他一切都被解釋為拒絕,並導致重復。
快速ACK:依次在事件發生後而不是經過完整的業務處理後響應2xx。
2)事件格式和強制性標題
有效載荷(示例)
json
{
"id": "evt_01HXYZ",
"type": "order. created",
"occurred_at": "2025-11-03T18:10:12Z",
"sequence": 128374,
"source": "orders",
"data": { "order_id": "o_123", "amount": "49. 90", "currency": "EUR" },
"schema_version": 1
}
發件人標題
"X-Bebhook-Id: evt_01HXYZ'是唯一的ID事件(用於重復數據消除)。
「X-Webhook-Seq:128374」是單調序列(按訂閱/主題)。
`X-Signature: sha256=
「X-Retry: 0.1.2……」-嘗試編號。
「X-Webhook-Version: 1」-合同轉讓。
(可選)「Traceparent」是跟蹤相關性。
收件人響應
2 xx-已成功接受(在此之後不會有重復)。
410 Gone-已刪除/處於非活動狀態→發件人停止重播並停用訂閱。
429/5xx/taymout-發件人重復轉發政策。
3)重復策略(retries)
推薦樓梯backoff(+jitter)
1 s、3 s、10 s、30 s、2 m、10 m、30 m、2 h、6 h、24 h'(在限制之後停止,例如48-72小時)。
規則:- 指數backoff+隨機夾具(± 20-30%)以避免「牛群效應」。
- 時間故障的錯誤定額(例如,如果5xx或網絡計時,則重播)。
- Respect 429:設置最低「min (Retry-After標題,下一個後退窗口)」。
Taymauts和尺寸
連接定時≤ 3-5秒;回復的總計時≤ 10秒。
根據合同(例如≤ 256 KB),否則為413 → 「chunking」或「pull URL」邏輯。
4)相似性和重復數據消除
相同的應用:處理相同的「id」的重復必須返回相同的結果,並且不得再次更改狀態。
收件人側面的滯後存儲:存儲'(X-Webhook-Id, , checksum)' TTL 後退窗口(24-72小時)。
組合鍵:如果有多個拓撲→「(subscription_id,event_id)」。
5)順序和「exactly-once效果」
在分布式系統中很難保證嚴格的順序。使用:- 按鍵分區:相同的邏輯集合(例如「order_id」)始終進入一個傳遞的「通道」。
- 序列:拒絕舊的「X-Webhook-Seq」事件,然後將其放入「停車位」,直到失蹤人員到來。
- 應用操作日誌(outbox/inbox pattern),
- DB中「event_id」上的事務性upsert,
- 復雜過程的傳奇/補償。
6)解決狀態代碼錯誤(表)
7)運河安全
每條消息的HMAC簽名;使用「時間窗口」(mitm和replay攻擊)檢查接收器。
敏感域的mTLS(KUS/付款)。
出站地址的IP allowlist,TLS 1。2+, HSTS.
PII最小化:不要發送多余的個人數據;偽裝成日誌。
保密輪換:兩個活動密鑰(active/next)和標題「X-Key-Id」以指示當前密鑰。
8)隊列、DLQ和接線
事件必須寫在發件人側面的輸出隊列/日誌中(以進行可靠的反射)。
當超出retrae的最大值時,該事件將因原因留給DLQ(死亡信條Queue)。
Replay API(針對收件人/操作員):通過「id」/時間/主題範圍重新發送, RPS限制和附加簽名/授權。
POST /v1/webhooks/replay
{ "subscription_id": "sub_123", "from": "2025-11-03T00:00:00Z", "to": "2025-11-03T12:00:00Z" }
→ 202 Accepted
9)合同和版本
轉化事件(「schema_version」字段)和傳輸(「X-Webhook-Version」)。
僅將字段添加為可選字段;刪除時-次要遷移和過渡期(雙寫)。
記錄事件類型、示例、模式(JSON Schema)、錯誤代碼。
10)可觀察性和SLO
發件人的關鍵指標是:- 「delivery_success_rate」(2 x/所有嘗試),「first_attempt_success_rate」
- `retries_total`, `max_retry_age_seconds`, `dlq_count`
- `latency_p50/p95` (occurred_at → ack_received_at)
- `ack_latency` (receive → 2xx), `processing_latency` (enqueue → done)
- `duplicates_total`, `invalid_signature_total`, `out_of_order_total`
99.9%的事件收到第一個ACK ≤ 60秒(28d)。
- DLQ ≤ 0.占總數的1%;24小時DLQ接≤。
11)時機與網絡中斷
在時間框中使用UTC;同步NTP。
發送「occurred_at」並捕獲「delivered_at」以計數差。
長時間中斷時,網絡/端點→在隊列中累積,限制生長(backpressure+配額)。
12)建議的限制及衛生
訂閱RPS(例如50 RPS,burst 100)+並發(例如10)。
馬克斯。屍體:64-256 KB;對於更多-「notification+URL」和下載簽名。
'snake中的事件名稱。case'或' dot。type` (`order.created`).
接收器寫操作的嚴格冪等性。
13)示例: 發件人和收件人
13.1發送者(偽代碼)
python def send_event(event, attempt=0):
body = json. dumps(event)
sig = hmac_sha256_base64(body, secret)
headers = {
"X-Webhook-Id": event["id"],
"X-Webhook-Seq": str(event["sequence"]),
"X-Retry": str(attempt),
"X-Signature": f"sha256={sig}",
"Content-Type": "application/json"
}
res = http. post(endpoint, body, headers, timeout=10)
if 200 <= res. status < 300:
mark_delivered(event["id"])
elif res. status == 410:
deactivate_subscription()
else:
schedule_retry(event, attempt+1) # backoff + jitter, respect 429 Retry-After
13.2收件人(偽代碼)
python
@app. post("/webhooks")
def handle():
body = request. data headers = request. headers assert verify_hmac(body, headers["X-Signature"], secret)
evt_id = headers["X-Webhook-Id"]
if dedup_store. exists(evt_id):
return, "" 204 enqueue_for_processing (body) # fast path. dedup_store put(evt_id, ttl=723600)
return, "" 202 # or 204
14)測試和混亂做法
負面案例:無效簽名,429/5xx,taymaut,410,大型付費。
行為:出局,復制,延遲1-10分鐘,間隙24小時。
負載:燒傷10 ×;檢查背壓和DLQ穩定性。
合同:JSON計劃,強制性標題,穩定事件類型。
15)實施支票
- 2xx=ACK,並在enqueue之後快速返回
- 指數backoff+jitter,尊重「Retry-After」
- 「X-Webhook-Id」(TTL ≥ retrai)的接收器和後座力)
- HMAC簽名、機密輪換、選項mTLS
- DLQ+Replay API、監控和Alertes
- 限制:taymauts,RPS,體型
- 順序:按鍵分區或「sequence」+「parking lot」
- 文檔:架構、示例、錯誤編碼、版本
- 混沌測試:延遲,雙打,網絡故障,冗長的重復
16)迷你常見問題
需要始終回答200嗎?
任何2 xx都算作成功。202/204是「排隊」的正常做法。
可以停止重播嗎?
是,響應410 和/或通過發送者控制臺/API(禁用訂閱)。
我該如何處理大包裹?
發出「通知+安全URL」,簽署下載請求並安裝TTL。
如何確保秩序?
Partition by key + `sequence`;當出現差異時-「停車位」和重播。
底線
可靠的webhooks是清晰的ACK語義(2xx),帶有backoff+ jitter的合理重復,嚴格的冪等性和重復數據消除,可讀的安全性(HMAC/mTLS),隊列+DLQ+後繼以及透明的可觀察性。確定合同,輸入限制和指標,定期運行混亂場景-您的集成將在第一次失敗時停止「湧入」。