IOSOR 知识库

重复的 webhook 绝不能产生第二笔扣款

失败路径:重试与回放对于预付费资金与收件箱保持幂等性——一个事件ID、一行扣款记录、一条收件箱条目。

至少一次投递机制将会进行重试。如果一个重复的 webhook 触发了第二笔扣款或第二条收件箱记录,这属于资金与运营事故,而非 «无害的确认»。本页面聚焦于失败路径:重试与回放必须在预付费资金和收件箱上保持幂等性,这与 API 发送幂等性短文或下行短信重试手册不同。

相关链接:签名与重放窗口网关、首次发送前的 webhook 契约、同一账本上的扣款行与送达状态。

IOSOR 提供白标预付费服务。充值 USD 20 即可针对单个消费者测试重复事件的烟雾测试;而在约 USD 1,000/month 左右的软审核会将 «重试即产生新收费» 视为对账债务。客户仅能看到白标事件 ID。

幂等性是失败路径而非口号

正常路径包含:一个已签名的事件、一个接受状态、一笔扣款。而失败路径则会损耗信任——包括超时、5xx 错误、提供商重放以及运营商重新推送。必须在产生副作用(如账本、收件箱、CRM)«之前»,从首次发送前的 webhook 契约中存储幂等键。软审核 USD 1,000/month 将 «确认后发明一个新键» 视为体量债务;而 USD 20 则证明了强制重放绝不会使资金翻倍。

哪些属于重复事件

信号 判定为重复的条件 安全结果
事件 ID 窗口内已接受相同的 ID 确认;无第二笔扣款
消息 ID 相同消息已关联账本 复用行;无新收费
收件箱键 相同的 MO/MT 已归档 无第二条收件箱行
越过重放窗口 门禁拒绝后的陈旧重试 拒绝;无资金或状态写入
未知类型 不在契约事件列表中 丢弃;无虚构的成功

签名与重放窗口网关负责判定真实性与时效性。本页面则负责处理有效重复事件 «之后» 的逻辑:单一的最终状态、一条资金流水线、一条收件箱记录。

资金绝不能移动两次

针对相同事件 ID 的第二笔扣款属于严重错误,即便产品 «仍显示已送达» 也是如此。财务部门会通过事件或消息 ID 进行过滤,并且在给定的 UTC 窗口内只能看到一行预付费记录。在持久化之后出现的局部副作用(例如先更新 CRM,后写入账本)会制造出虚假的双重真相。如果在持久化之后处理失败,应当在相同的键上重试工作进程,绝不能将 HTTP 请求体作为新的收费再次接受。在重复事件测试显示 «仅有一行» 账本记录之前,软体量相关表述将一直处于受阻状态。

收件箱也绝不能双倍生成

幂等性不仅关乎资金。被重放的上行或送达事件如果开启了第二条收件箱线程,会迫使客服人员去追查幽灵消息,甚至可能触发自动回复循环。应当使用用于扣款的相同事件 ID 来存储收件箱键。产品与财务部门会共用拒绝或重复相关的术语:产品与财务的共享状态语言。USD 20 的测试证明了强制重放不会改变收件箱的基数。

买家防重复 webhook 检查清单

  1. 幂等键的形态是否已在契约中达成一致并在产生副作用之前存储?
  2. 窗口内的重复事件 ID 是否能够实现确认而不产生第二笔扣款?
  3. 相同消息 ID 是否绝对不会开启第二行预付费账本记录?
  4. 收件箱插入是否使用相同的键进行键控,从而在重放时不会产生第二个线程?
  5. 签名失败与窗口拒绝是否能够与真正的重复事件分开统计?
  6. 在重复事件测试未通过呈红灯状态时,是否暂停了关于软审核 USD 1,000/month 的讨论?

任何一项回答为 «否» 都会让防重复的 webhook 资金——以及受信任的收件箱——停留在草稿阶段。

从 IOSOR 开始

在已扣过款的通道上,窗口内强制重放一条带签名的 webhook。把事件 id 和 ledger id 并排导出,证明只有一行扣款、一行收件记录。若出现第二笔扣款,停掉该消费者并退回多余行,禁止拿后续流量去对冲。这是重放记账闸,不是 E.164 语法检查,也不是物流文案。

IOSOR 要点

重放不是新发送。一个事件 id 只写一笔扣款。

要做:签名与重放窗口开着,窗口内 POST 后只证明一笔扣款。不要:每个 POST 都扣,或把网络重试当成第二张账单。

这篇指南有帮助吗?

相关指南