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+后继以及透明的可观察性。确定合同,输入限制和指标,定期运行混乱场景-您的集成将在第一次失败时停止"涌入"。