Platform

失败的 webhook 如何重试?事件是否按顺序到达?

Bird 按固定时间表重试失败的 webhook,但不保证事件按发生顺序到达。

即使发送方从未收到确认,你的接收方仍可能已存储了事件。因此,重试可能会重复你的应用已经处理过的工作。

重试会延迟某些事件。较新的事件可能在重试完成前到达。存储事件标识符和发生时间,以防止这些投递覆盖较新的数据。

什么算作投递失败?

Bird 在收到非成功响应或请求超时时,将投递视为失败。

在存储事件后返回 HTTP 2xx 以停止该投递的重试。重定向、客户端错误或服务端错误仍有资格被重试。

例如,400 记录了一个被拒绝的请求,但不会通知 Bird 丢弃它。当签名验证或持久化存储失败时,使用错误响应,以便该投递可以被恢复。

在确认之前先存储事件。如果先返回成功,后续的存储操作失败,事件就会丢失。

将耗时的处理放到后台工作进程中,以便接收方能及时响应。接收方的职责是在处理开始前验证并保存事件。

重试时间表是什么?

Bird 在首次尝试后使用七个重试间隔,总共八次尝试。

重试距上次尝试的间隔时间调整前的大致累计时间
15 秒5 秒
25 分钟5 分 5 秒
330 分钟35 分 5 秒
42 小时2 小时 35 分 5 秒
55 小时7 小时 35 分 5 秒
610 小时17 小时 35 分 5 秒
710 小时27 小时 35 分 5 秒

该时间表给你大约 27.5 小时来修复接收方,之后自动尝试将结束。

Bird 对每次等待时间随机调整最多 20%(上下浮动),以在故障后分散重试。因此,5 分钟的间隔在其他调整之前实际范围为 4 到 6 分钟。

限流响应或超时可能改变下一次等待时间。Bird 还会参考 Retry-After,这是一个请求在下次尝试前延迟的响应请求头。将该时间表视为恢复窗口,而非精确的截止时间。

每次重试保留事件的 webhook-id,因此你的接收方可以识别重复投递

最后一次重试之后会怎样?

该投递的自动重试到此结束。您可以请求重放失败的投递。

通过 createWebhookReplay 或端点的仪表盘页面请求重新投递。重放读取投递尝试日志,选取其中失败的事件。Bird 从未被尝试过的事件(例如端点暂停期间到达的事件)没有尝试记录可供选取,因此重放无法恢复它。

响应为 202,表示重放已排队等待后台执行。响应中不包含计数或任务标识符。使用 listWebhookAttempts 检查后续的尝试。

每次重新投递只尝试一次,而非按上述重试计划执行。Bird 会记录该尝试并完成任务,无论接收端是否成功接受。因此,向仍然故障的接收端重放,每个事件只消耗一次请求而非八次。先修复接收端,然后再次重放。这些失败不会影响端点健康状态。成功接受的重新投递会清除降级状态。

重放会跳过已成功确认的投递。重新投递保留其原始 webhook-id,因此您的去重逻辑仍然适用。

sinceuntil 设置为日期时间字符串以界定恢复窗口。两个边界均为包含式。两者都按投递尝试的时间读取,而非事件发生的时间。省略 since 会将窗口起点设为请求前 24 小时,因此更早的故障需要显式指定起始时间。省略 until 会将窗口终点设为请求发出的时间。

尝试记录保留三天,这也是重放所能追溯的最远时间。更早的 since 会扩大时间窗口,但无法恢复更早的事件。单次重放最多覆盖窗口内最早的 10,000 个事件,因此较长的中断需要拆分为多个较窄的时间窗口。

每个组织每 UTC 日最多可请求 20 次重放。超出后请求会收到 429WebhookReplayQuotaExceeded,因此应将恢复合并到一个窗口中,而不是逐事件请求重放。

如果我的端点持续失败怎么办?

Bird 会将持续失败的端点标记为降级。连续失败约五天后,它会暂停投递。

您可以读取其 status,值为 activedegradedpaused。降级端点继续接收投递和重试。一次成功的投递会清除降级状态并重置连续失败计时器。

暂停的端点停止接收事件,且不会自动恢复。使用 updateWebhook 重新启用它,将 status 设置为 active。然后重放该窗口,以恢复暂停前失败的投递。请先重新启用:端点仍处于暂停状态时请求重放会返回 202,不会重新投递任何内容。可写的状态值为 activepaused

更改接收 url 或完成一次成功的测试投递也会清除降级状态。替换 URL 必须是可公开访问的 HTTPS,因此私有地址无法修复可达性问题。超过 2048 个字符的 URL 会验证失败,请在提交前缩短生成的 URL。

编辑端点的描述或事件订阅并不能证明它可以接收请求。这些更改不会清除降级状态,失败的测试投递也是如此。

Bird 会在端点进入降级状态时向组织所有者发送邮件。在端点恢复之前不会再发送降级邮件。因此,反复失败不会为每次尝试都生成一封邮件。恢复后再次失败会开启新一轮降级。

是否有死信队列?

Bird 不提供单独的失败事件队列供您读取。请检查投递尝试记录并请求重放。

恢复任务机制
检查失败投递尝试记录每个 HTTP 请求的结果和延迟,按最新排列。
停止向故障接收端重复投递暂停可将端点移出投递流程。
恢复失败的投递重放在指定时间窗口内请求重新投递。

修复接收端,必要时重新启用它,然后重放受影响的窗口。之后没有单独的队列需要排空。

事件是否按顺序到达?

事件到达的顺序可能与其发生的顺序不同。

email.delivered 事件可能在同一消息的 email.accepted 事件之前到达。在应用可能覆盖较新状态的变更之前,先比较 timestamp 中的事件时间。

分别跟踪 SMS 费用的每个组成部分。例如,投递费用和运营商费用是独立的费用组件。

cost 对象在组件定价之前为 null。其组件值为十进制字符串或 null。amount 字段是一个十进制字符串,汇总该载荷中已有的组件。

使用每个组件最新的事件时间戳进行合并。替换整个对象可能会擦除另一个事件提供的组件,或恢复旧的费用。

null 组件表示该载荷中未定价,而非费用为零。SMS 事件描述了该合并的上下文,webhooks 涵盖投递语义。

简而言之

  1. 重试使用固定时间表。

    八次尝试在时间调整前大约跨越 27.5 小时。等待时间的随机变化使重试分散开来,避免接收方面临同步的突发请求。

  2. 在持久化存储后再确认。

    2xx 响应会停止重试,并将该投递排除在遗漏事件重放之外。错误响应使其仍有资格被重试。

  3. 已暂停的端点需要手动恢复。

    重新启用端点,然后重放暂停前失败的投递。端点暂停期间到达的事件从未被尝试投递,因此重放无法覆盖它们。

  4. 使用事件时间来应用更新。

    投递是无序的。比较事件发生时间戳,并按组件合并 SMS 的部分费用。

基于同一网络构建。

测试 API 密钥即刻获取。添加付款方式并验证发送者身份后,即可解锁生产环境。

你的下一个创意。
随时连接。