返回

文章详情

Webhook的峡谷

Hacker News2026年8月5日 15:22

我已经在三家不同的公司为三家不同的服务提供商构建了同样的系统三次。这个系统从来没有名字,也从未出现在路线图上,但它总是朝同一个方向发展:关于您自己客户的真实信息存储在别人的数据库中。用户驻留在身份提供者中,订阅信息在Stripe中,跳转邮件在任何发送您邮件的地方,而您的产品需要在本地获取这些真实信息。因此,您订阅webhook并保留一份副本。第一次,我以为我只是在构建一个端点:一个解析JSON并更新行的路由,一个下午的工作。这个下午变成了一周。首先是签名验证,因为一个会改变您数据库的开放端点是个漏洞。然后是去重表,因为投递信息有时会重复到达,文档乐观地称之为“至少一次”。然后处理程序得到了一个缓冲区,因为membership.created有时会在user.created之前出现。接下来是引导导入程序,因为webhook只会在您订阅后告诉您发生了什么,它会和实时事件竞速,因此它需要一个锁定方案。最后是调和定时任务:一个在凌晨三点抓取提供者列表API的工作,比较与我们的数据库,安静地修复不一致之处。我想诚实地说明这个定时任务是什么。它是一份书面自白。它说:我不信任我构建的副本,我没有办法知道何时它是错误的,因此我将永远每晚从零开始重新推导它。失去信任是有原因的。漂移从不自我通知;我们的漂移是通过一张支持票发现的。一位客户几个月前已经取消了,但我们的数据库依然显示为活跃;一些customer.subscription.deleted在Stripe和我们之间蒸发了,没有任何地方能够注意到:他们的仪表板显示投递已重试并最终丢弃,而我们的日志不能记录一个从未到达的请求。这仅仅是代码。每个提供者还带来了他们自己的仪表板。三个提供者,三个webhook配置页面,每个都有自己对如何注册端点、哪些事件存在、如何区分测试和实时环境以及签名密钥存放在哪里的想法。当出现问题时,调试就像一次旅行:一个标签页是他们的投递日志,另一个是我们的日志,第三个标签页是我当前怀疑的任何仪表板。它们都不一样,所有都必须检查。当我第三次构建这个系统时,我已经停止假装。我事先为整个技术栈做了预算(签名、去重、缓冲、引导、定时任务),在我写第三个去重表的过程中,终于问了我应该在第一次就问的问题。我究竟在重构什么?通知并不是我在重构数据的有序日志。每个集成都试图将一系列通知转回有序的、完整的、当前的历史记录。而荒谬的是:这个历史记录确实存在。它必须存在,因为它就在提供者内部;它就是他们渲染仪表板、事件页面和webhook重放工具的方式。提供者将有序日志拆分成单个HTTP POST,通过一个既不保证顺序也不保证投递的通道发送到我的端点,然后我在这边重新组装日志。其他所有消费者也是如此,每个都有自己的bug。这是一幅拼图,制造商有原始图片,剪碎了,将碎片一次邮寄给我,在邮寄过程中丢失了一些,邮寄了一些两次,盒子上却什么也没有印刷。当我组装好的拼图不匹配原始拼图时,他们的支持团队问我缺少哪些碎片。我不知道,这就是整个问题:没有任何东西会宣布缺失。这不是任何提供者的bug。他们的webhook工作方式与文档描述完全一致。问题在于webhook是什么:一种通知,“发生了什么,给你一个关于它的POST”。通知是一种触发副作用的好方法,但却是传输数据集的糟糕方法,在某个地方,我们开始在没有注意到我们已改变工作的情况下使用它们来做第二件事。这怎么会成为常态?没有人做出这个决定。术语“webhook”是Jeff Lindsay在2007年创造的,早期的用法确实非常合适:GitHub的post-receive hooks启动CI构建,或者支付事件向您的服务器发送ping以便可以发送收据。工作是当事情发生时做某件事,对于这个POST是完美的:不管是发送和遗忘,当遗忘是可以接受的时。webhook的传播是因为它们是提供者能发布的最便宜的东西(一个HTTP POST),也是消费者能接收的最便宜的东西(您已经有了网络服务器,所以只需添加一个路由)。到2010年代早期,“我们有webhook”成为每个API主页上的复选框,而这个复选框从未区分两种非常不同的工作:触发副作用:发送收据,启动构建,ping通道。

赞助内容

NordVPN Next-gen Antivirus

本站免费、广告极少。如果觉得有帮助,可以请我们喝杯咖啡 —— 任何金额都对持续运营有实际帮助。

请我喝杯咖啡