Webhook2026年11月3日9 分钟阅读

Shopify Webhook 重试实测:4 小时 9 次,之后再无

我们故意让 Shopify Webhook 失败,并记录了每一次重试:4 小时内共投递 9 次,之后什么都没有,服务器恢复后也没有。

接收端返回 503已恢复SHOPIFY 直连第 9 次,4 小时8 分钟内 5 次尝试此后什么都没有经过 ANYHOOK第 4 次,3 小时 35 分钟第 5 次,21 小时 35 分钟:已送达06小时12小时18小时1天
四个测试订单,接收端宕机了不到六个小时。Shopify 的最后一次尝试,比接收端恢复早了约两个小时。

Shopify 对失败的 Webhook 一共投递 9 次:第一次尝试加 8 次重试,最后一次在事件发生 4 小时后。然后就停了。在我们的测试里,哪怕服务器恢复了,这些订单也再没有任何投递。订单在 Shopify 里还在,但你的系统通过 Webhook 永远收不到它们。

Shopify 的文档只给了总数,4 小时内重试 8 次,没说每次尝试发生在什么时候。所以我们自己测了一遍。我们在一个 Shopify 开发商店下了四个测试订单,让接收端对所有请求返回 503,持续不到六个小时,并记录了每一个请求。

TL;DR

  • 各次尝试落在约 2 秒、3 秒、1 分钟、3 分钟、8 分钟、30 分钟、1 小时、2 小时和 4 小时。四个订单的时间点相差都在 1.4 秒以内
  • 第九次尝试之后,什么都没有。接收端不到两小时后恢复,四个订单没有一个通过 Webhook 送达
  • 许多指南至今还在写的“48 小时内重试 19 次”已经过时
  • 在 Shopify 后台添加的 Webhook,连续投递失败 36 次后也没有被删除。后台页面没有显示任何失败,店主也没有收到邮件
  • 要扛过超过四小时的宕机,需要两样东西:在你的服务器宕机时保存事件并应答 Shopify 的一层,以及一个对 Admin API 的对账任务。对于在后台添加的 Webhook 或小型应用,改动最小的办法是用 AnyHook 这样的转发服务:你只需改一个 URL

实测的重试时间表

尝试下单后的时间与上一次尝试的间隔
12 秒
23 秒1 秒
31 分钟1 分钟
43 分钟2 分钟
58 分钟5 分钟
630 分钟22 分钟
71 小时30 分钟
82 小时1 小时
94 小时2 小时
之后没有

时间从 X-Shopify-Triggered-At 算起,这是 Shopify 打在 Webhook 上的时间戳。

九次尝试里有五次集中在前八分钟。它们能应付一次短暂抖动,却应付不了一次出错的部署:等有人看到告警时,只剩四次了。

这个时间表看起来是固定的。每一次尝试,四个订单的到达时间都相差在 1.4 秒以内,看不出抖动。同时失败的一批订单,会作为同一批重试:限时抢购的流量高峰,会在一分钟后、三分钟后、八分钟后原样再来一遍。

同一个事件的重试带着相同的 ID。在我们对比的那个订单上,X-Shopify-Webhook-Id 在九次尝试中完全一致,所以它是去重的可靠键。

关键的界线是四小时。端点恢复时,过去四小时内的每个订单都还在路上,会在各自的下一次计划尝试时送达。比这更早的订单,永远不会送达。

“48 小时内重试 19 次”已经过时

你仍会看到这个数字,包括 Webhook 厂商今年发布的指南。它来自 Shopify 以前的策略。Shopify 在2024年9月10日改了这套机制,变成 4 小时内重试 8 次,现行文档的说法也一致。我们的日志与此相符:最后一次尝试发生在第四个小时,第二天也没有收到更多投递。

如果你的运维手册或恢复预案是按两天来算的,就差了十二倍。

订单后来怎么样了

在直连的 Webhook 上,全部 36 次投递(四个订单,每个九次尝试)都收到了 503。接收端在这些尝试的最后一次之后 1 小时 37 分钟重新开始返回 200,Shopify 没有再试。四个订单没有一个送到。

这次宕机没有任何特别之处。周五晚上一次出错的部署,在午夜前修好,看起来也是这样。丢哪些订单,取决于你宕机了多久。在一次六小时的宕机里,前两小时的订单在 Webhook 这条路径上就没了,后四小时的订单会在各自的下一次计划尝试时送达,最晚在你恢复后两小时。这说的是一个在宕机中幸存下来的 Webhook。通过 Admin API 创建的订阅,可能在这期间被删除,之后在你重新创建之前,不会再发送任何新事件。

把这个放到黑色星期五大促中:服务器压力最大,每小时的订单也最多,最前面那几个小时只能靠 Admin API 回填,没有别的办法能找回来。具体步骤见 Shopify 删除了你的 Webhook 订阅。

Webhook 还在,但没有人收到通知

Shopify 的文档说,只有通过 Admin API 配置的订阅,才会在连续失败 8 次后被删除,而警告邮件会发到应用的紧急开发者邮箱。文档没有提到在 Shopify 后台的 Settings → Notifications → Webhooks 里手动添加的 Webhook。它们背后没有应用,而且往往正是把店铺连到 ERP 或仓库系统的那条线。

所以我们去看了。连续 36 次投递失败之后,第二天:

  • 这个 Webhook 还在列表里,没有任何变化
  • 后台页面没有显示投递记录,也看不出失败。每一行只提供编辑、发送测试和删除
  • 店主的邮箱没有收到任何警告邮件

一个已经整整一天每次投递都失败的 Webhook,看起来和一个健康的没有区别。唯一的症状是下游缺订单。通过 Admin API 创建的订阅,失败的方式不一样:Shopify 会把它删除。

宕机超过四小时,怎么保住订单

你需要一个在服务器宕机时保存事件并应答 Shopify 的一层,再加一个对账任务,兜住仍然漏掉的部分。Shopify 自己的文档也建议你建这个任务。下面的选项里有一个是我们做的,请相应地看待我们的意见。

方案适用于后台添加的 Webhook适合谁代价
基于 Admin API 的对账任务是任何漏一个订单就要花钱的店铺事后才运行,按你的计划来。要自己建、自己运行
Amazon EventBridge 或 Google Pub/Sub否,后台表单只接受 URL已经在该云上的应用只支持应用订阅。消费端、保留期和告警都要自己建
自建队列,前面放一个小端点是想把一切都放在内部的团队这个端点同样只有五秒应答时间,而且在你系统的其余部分挂掉时它必须还活着
Hookdeck是需要数据转换、团队协作流程和大流量的平台团队对于“重试加重放”这点需求来说,产品太重
AnyHook是小团队和后台添加的 Webhook:只改一个 URL,无需写代码,免费开始投递是至少一次,所以你仍要去重。Free 套餐在第 35 分钟停止重试,每天超过 1,000 个事件也会拒收

怎么选:

  • 你是手动添加的 Webhook,或者运行一个小型应用,想让订单扛过一个糟糕的夜晚: 在你的端点前面放一个转发服务。AnyHook 就是为这种情况做的。只改一个 URL,你的处理程序保持原样
  • 你是处理大流量的平台团队: Hookdeck 是更完整的产品。两者的对比在这里
  • 你的应用已经跑在 AWS 或 Google Cloud 上: EventBridge 或 Pub/Sub 正好适合你现有的环境
  • 无论哪种情况: 都要保留一个订单对账任务。转发服务会把那条界线从四小时挪到它自己的重试窗口和保留期,但这条界线依然存在

同样的测试,经过 AnyHook

AnyHook 是一个 Webhook 转发服务:你把 Webhook 指向它,它保存事件、应答发送方,再转发到你的服务器,你的服务器失败时会重试。在这次测试里,每个订单还发给了第二个 Webhook,它指向 AnyHook,由 AnyHook 转发到同一个接收端:

尝试经过 AnyHook
12 秒
25 分钟
335 分钟
43 小时 35 分钟
521 小时 35 分钟,已送达

AnyHook 约 1 秒就给 Shopify 返回 200,所以 Shopify 没有什么可重试的,这个时间表是 AnyHook 自己对同一个失败的接收端的重试。直连 Webhook 上 Shopify 的尝试早已结束很久之后,第五次尝试发现接收端已经恢复,把仍在等待的三个订单送达了。第一个订单的那一份已经在 35 分钟时送达,原因是我们这边的一次失误,见测试方法。

这一跳给第一次尝试增加了 0.5 到 0.9 秒。Shopify 的签名经受住了转发:接收端对转发过来的请求验证原始的 X-Shopify-Hmac-SHA256,每一次都通过,所以你现有的验证代码照常可用。AnyHook 在第一次投递失败时发了邮件,连续失败五次时又发了一封。Shopify 什么都没发。

这次测试跑在我们自己的 Enterprise 账号上。各个套餐的重试时间点相同。不同的是你能得到几次尝试,以及能重放多久:

套餐价格尝试次数最后一次自动尝试重放窗口
Free$0,无需绑定信用卡335 分钟3 天
Pro$20/月521 小时 35 分钟30 天
Scale$90/月105 天 21 小时90 天

在 Free 套餐上,这次测试的结果会不同:重试在 35 分钟停止,那时接收端还没恢复。订单仍然在日志里,你需要在三天内手动重放它们。Free 套餐每天超过 1,000 个事件也会拒收,所以不适合用来扛大促。Pro 套餐没有每日上限,第五次尝试的表现和这次一样。

转发服务是你订单路径上多出来的一方。AnyHook 在应答之前,会先把每个事件静态加密并保存。如果它无法保存某个事件,就返回 503 而不是 200,由 Shopify 自己的重试接手。

接入步骤

  1. 在 AnyHook 中创建一个 App,把你现在的 Webhook URL 设为它的目标地址。想先不注册账号看一看,可以用下面的命令,它会返回一个可用的 inbound_url、一个 API 密钥和一个 claim_url。除非你打开认领链接并登录,否则这个端点和它的事件会在 7 天后删除:

    curl -X POST https://anyhook.net/api/v1/quickstart
    
  2. 在 Shopify 后台打开 Settings → Notifications → Webhooks → Create webhook。选择事件,把格式设为 JSON,粘贴 AnyHook 的入站 URL。

  3. 把该页面上显示的签名密钥,复制到 App 的来源签名密钥中,然后在这个 Webhook 的菜单里发送一次测试。它应该出现在 App 的日志里,而伪造的请求会收到 401。你的应用创建的订阅,则改用应用的 client secret 签名。

AI 编程智能体可以用 npx -y anyhook-mcp 完成第一步。

FAQ

Shopify Webhook 失败后会重试几次?

首次尝试之后重试 8 次,也就是一共 9 次投递,持续 4 小时。我们测得各次尝试发生在事件之后约 2 秒、3 秒、1 分钟、3 分钟、8 分钟、30 分钟、1 小时、2 小时和 4 小时。

Shopify 的 Webhook 现在还会重试 48 小时吗?

不会。旧指南里的“48 小时内重试 19 次”,早于 Shopify 在2024年9月做的那次改动。在我们2026年11月的测试里,最后一次尝试发生在第四个小时。

服务器恢复后,Shopify 会补发 Webhook 吗?

只有在事件的各次尝试还没走完时才会。在你恢复前不到四小时发生的事件,会在它的下一次计划尝试时送达。更早的事件不会再发,你需要从 Admin API 把它取回来。

Shopify 怎样算 Webhook 投递失败?

根据 Shopify 的文档,200 范围之外的任何响应都算,包括 3xx 重定向,还有五秒内没有应答的情况,其中连接允许占一秒。我们的测试只用了 503 响应。

Webhook 一直失败,Shopify 会把它删除吗?

根据 Shopify 的文档,通过 Admin API 创建的订阅,连续失败 8 次后会被删除。在我们的测试里,一个在 Shopify 后台添加的 Webhook,连续失败 36 次之后的第二天,仍然在列表里。

Webhook 失败时,Shopify 会发告警吗?

对于应用订阅,警告邮件会发到应用的紧急开发者邮箱。对于我们在后台添加的那个 Webhook,店主没有收到任何邮件,后台页面也没有显示失败。

Shopify 不再重试的订单,怎么找回来?

用 Admin API 查询宕机时间段内的订单,把结果交给你平时的处理程序,并开启去重。步骤见 Shopify 删除了你的 Webhook 订阅。

服务器宕机期间,怎样保住 Shopify 的 Webhook?

在你的端点前面放一个 Webhook 转发服务或队列:它应答 Shopify,保存事件,并用更长的时间表重试你的服务器。对于在后台添加的 Webhook 或小型应用,AnyHook 改动最小,只改一个 URL,有免费套餐,付费套餐的重试时间更长,也没有每日上限。Hookdeck 适合需要数据转换和团队协作流程的平台团队。跑在 AWS 或 Google Cloud 上的应用,可以把订阅改发到 EventBridge 或 Pub/Sub。无论哪种情况,都要保留一个对 Admin API 的对账任务。

测试方法

我们在2026年11月2日做了这次测试,用的是一个 Shopify 开发商店,API 版本 2026-10,主题 orders/create。两个 Webhook 都是在后台添加的。接收端是一个 Cloudflare Worker,记录每一个请求,在 17:43 UTC 之前返回 503,之后返回 200。四个订单在 11:46 到 12:06 UTC 之间下的。

直连 Webhook 上的确切到达时间,单位是距 X-Shopify-Triggered-At 的秒数:

尝试四个订单的范围
11.4 到 1.9
22.3 到 2.9
363.3 到 64.2
4183.6 到 185.0
5484.4 到 485.8
61805.4 到 1806.5
73606.2 到 3607.4
87207.0 到 7208.2
914407.7 到 14409.0

有两处不完美。我们这边的一次失误,让接收端在 12:20 UTC 前后恢复了几分钟。直连的尝试没有一次落在这个时间窗口里,但第一个订单经 AnyHook 的那一份落在了里面,所以这个订单没有计入 AnyHook 的结果。另外,接收端是中途才开始检查签名的,所以两条路径上最早的几次尝试都没有经过检查。

我们没有测试超时或连接被拒绝,只测了快速返回的 503。我们没有测试通过 Admin API 创建的订阅,所以上面的删除规则来自 Shopify 的文档。我们没有测试正式店铺,也没有测试大流量。四个订单是个很小的样本,不过这样规整的时间表不太可能是噪声。Shopify 随时可能改动其中任何一项,所以请核对上面的日期。

全部文章2026年11月3日 · 9 分钟

别再丢 Webhook 了。

只改一个 URL。获得重试、事件日志和一键重放。也可以先亲眼看看:注册后跑一次 30 秒的故障演练,看一个事件如何挺过你的服务器宕机。不需要服务器。