webhook 和 API:你了解吗

Webhooks 是许多 API 的补充。通过设置 webhook 系统,系统 B 可以注册接收有关系统 A 某些更改的通知。当更改发生时,系统 A 推送 更改到系统 B,通常是以发出 HTTP POST 请求的形式。

Webhooks 旨在消除或减少不断轮询数据的需要。但根据我的经验,webhooks 带来了一些挑战。

通常,您不能单靠 webhooks 来保持两个系统的一致性。我参与过的每一个集成项目最终都意识到这一点,并通过轮询增强了 webhooks。这是由于几个问题领域。

首先,当您的系统宕机时存在风险。是的,发送者通常会用某种指数退避重试未送达的 webhooks。但保证往往是宽松或不明确的。而且系统从灾难中恢复后,最不需要的可能就是处理积压的 webhooks 大量任务。

其次,webhooks 是短暂的。它们太容易处理不当或丢失。如果您在部署代码更改后意识到您输入了一个错误的 JSON 字段,并且正在将 null 插入到您的数据库中,那么您无法回放 webhooks。或者,您可能会在 webhook 请求之外处理部分 webhook 处理流程——比如数据库插入。但那样您就冒着失败并丢失 webhook 的风险。

为了缓解这两个问题,许多开发人员最终将 webhooks 缓存在像 Kafka 这样的消息总线系统上,这感觉像是一个笨重的妥协。

考虑两方之间复杂的 webhook 管道结构:

我们在发送端和接收端各有一个消息总线。复杂性显而易见,而且可能出问题的阶段很多。例如:在接收端,即使您的系统运行良好,您仍然可能受到发送者可交付性失败的影响。如果发送者的队列开始经历背压,webhook 事件将被推迟,而您可能很难知道这种滑移正在发生。

增加复杂性的是,两者之间的安全层通常是某种 HTTP 请求签名协议,如 HMAC。这很稳固且减轻了管理秘密的负担。但对于您的普通开发人员来说,这也不太熟悉,因此更容易头疼和出错。(HTTP 请求 签名和验证是那些任务之一,我觉得一个人做得不够频繁,以至于永远不会完全记住。)

因此,不仅仅是 webhooks 使您最终面临不一致,它们对每个人来说也是更多的工作。

那么我们还能用什么来保持两个系统的同步呢?

/events 接口

要寻找保持两个数据集和谐的灵感,我们不妨看看数据库。考虑 Postgres 的复制插槽:您为每个从数据库创建一个复制插槽,从数据库订阅该复制插槽以获取更新。

两个关键组成部分是:

  • 主数据库保持最近变更的日志
  • 主数据库保持一个游标,跟踪每个从数据库在更改日志中的位置

如果从数据库宕机,当它恢复时,可以自由地翻阅历史记录。没有队列,也没有在每端尝试像接力棒一样传递事件的工人。

API 也可以遵循这种模型。以 Stripe 为例。他们有一个 /events 接口,包含过去 30 天内对 Stripe 帐户进行的所有创建、更新和删除操作。每个事件对象都包含所操作实体的完整有效载荷。这里有一个事件的示例,针对一个 subscription 对象:

 

{ "id": "evt_1J7rE6DXGuvRIWUJM7m6q5ds", "object": "event", "created": 1625012666, "data": { "object": { "id": "sub_JgFEscIjO0YEHN", "object": "subscription", "canceled_at": 1625012666, "customer": "cus_Jff7uEN4dVIeMQ", "items": { "object": "list", "data": [ // ... ], "url":"/v1/subscription_items?subscription=sub_JgFEscIjO0YEHN" }, "start_date": 1623826800, "status": "canceled", } }, "type": "customer.subscription.deleted" }

一些重要的特质:

  • 每个事件有一个 type,告诉我们这个事件是什么。在这个案例中,我们看到一个客户的订阅已被删除。因为包含了完整的订阅有效载荷,我们可以更新我们的数据库以反映字段如 canceled_at 和它的新 status 为 canceled
  • 每个嵌入对象包含一个 object 字段,所以我们可以轻松地提取和解析它们。
  • 事件对象大量嵌入子对象,让我们全面了解所有变化,无需轮询 API

因此,我们可以轮询 /events 来保持事物的最新状态,而不是监听 webhooks。我们只需在本地保持一个游标,我们在请求中使用它来指示给 Stripe 我们已经看到了哪些事件。

优势:

  • 如果我们宕机,我们不用担心错过 webhooks。当我们恢复时,我们可以自己的步调赶上。
  • 如果我们部署了一个错误地处理事件的错误,不用担心。我们可以部署修复,并为 /events 倒带游标,它将回放它们。
  • 我们端不需要消息总线。
  • 我们不必担心 Stripe 的 webhook 发送者延迟交付。速度掌握在我们手中。我们与最新数据之间的唯一障碍是 Stripe 在 API 层面所做的任何缓存(看起来是没有的)。
  • 我们使用简单的基于令牌的身份验证方案。
  • 我们拉取和处理事件的方式与我们处理任何其他端点的方式相同。我们可以重用许多相同的 API 请求/处理代码。

在生产者端,为了支持 /events,您需要添加监控创建/更新/删除的同样仪式,就像您会为 webhooks 使用的那样。除了,您不需要构建交付管道,您只需要将记录插入到一个仅追加的数据库表中。

在消费者端,您将需要设置一些轮询基础设施。这比如说,一个处理一切的基本 webhook 处理端点需要更多的基础工作。但是,我敢打赌一个像样的轮询系统构建起来并不比一个健壮的 webhook 处理系统难,例如,一个带有消息总线的系统。而且您得到了更好的一致性保证。

使 /events 更好

在 /events 接口中有一个明显的低效之处:为了尽可能保持实时性,您必须非常频繁地轮询。我们每个帐户每 500 毫秒轮询一次 Stripe /events 端点,并考虑将其减半。

这些请求很轻,因为对于大多数活跃的 Stripe 帐户来说,响应往往是空的。但作为程序员,我们不禁想寻找一种更有效的方式。

对于 Stripe 和其他 API 平台来说,一个创意:支持长轮询!

在长期被遗忘的长轮询艺术中,客户端发出标准的 HTTP 请求。如果服务器没有新的信息需要传递给客户端,服务器将请求保持开放,直到有新的信息要传递。

在我们与 Stripe 的集成中,如果我们可以请求 /events 并指出我们希望进行长轮询,那会很好。根据我们发送的游标,如果有新事件 Stripe 将立即返回这些事件。但如果没有,Stripe 可以保持请求开放,直到创建了新事件。当请求完成时,我们只需重新打开它并重复循环。这不仅意味着我们可以尽快获得事件,还可以减少总体网络流量。

长轮询相对于 websockets 的优势在于代码重用和简单性。大多数集成本来就涉及某种形式的轮询,无论您是在回填数据还是重播错误处理的事件。能够通过单一参数调整从例如回填切换到实时监听新事件的能力是一个巨大的胜利。

我应该使用哪个?

对于 API 消费者来说,如果您幸运地有选择使用轮询 /events 或使用 webhooks 的选择,那么该选择使用哪个主要取决于您的一致性需求。Webhooks 可以更快地开始使用,特别是如果您只关心几个 API 对象。对于某些工作流程,如果 webhooks 被丢弃也没关系,比如您正在向 Slack 频道发布“新订阅者”公告。

但随着集成的重要性增长以及确保不丢失任何东西的需求出现,我们认为轮询 /events 很难被超越。

对于 API 生产者来说,支持 /events 不仅是给您的 API 消费者的一份大礼。/events 可以轻松成为提供 webhooks 的跳板。您的 events 表可以作为您的 webhook 发送者的出站工作的“队列”。事实上,/events 可以解锁急需的 webhook 功能,比如允许您的 webhook 消费者重放或重置其 webhook 订阅的位置。

  • 源于:Give me /events, not webhooks

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/705206.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软考一年只能考一次吗?24软考各科目考试时间一览表

软考考试次数: 软考高级【系统分析师】及【系统架构设计师】是一年考两次的。 此外,软考中级【软件设计师】和【网络工程师】也是一年考两次的。 其他科目一年都只开考一次,或者上半年开考,或者下半年开考,具体考试…

k8s 二进制安装 优化架构之 部署负载均衡,加入master02

目录 一 实验环境 二 部署 CoreDNS 1,所有node加载coredns.tar 镜像 2,在 master01 节点部署 CoreDNS 3, DNS 解析测试 4, 报错分析 5,重新 DNS 解析测试 三 master02 节点部署 1&#xff0…

DeepSpeed

文章目录 一、关于 DeepSpeed1、DeepSpeed 是什么2、深度学习训练和推理的极致速度和规模3、DeepSpeed 的四大创新支柱1)DeepSpeed 训练2)DeepSpeed 推理3)DeepSpeed 压缩4)DeepSpeed4Science 4、DeepSpeed 软件套件DeepSpeed 库推…

Golang RPC实现-day02

导航 Golang RPC实现一、客户端异步并发多个请求1、 客户端结构体2、 一个客户端,异步发送多个请求,使用call结构体代表客户端的每次请求3、客户端并发多个请求4、客户端接收请求 Golang RPC实现 day01 我们实现了简单的服务端和客户端。我们简单总结一…

景源畅信电商:做抖音有哪些未开发的蓝海领域?

在互联网信息爆炸的今天,抖音已经成为人们获取信息和娱乐的重要渠道。然而,随着用户数量的增加和内容的丰富,抖音的红海竞争也日益激烈。在这样的背景下,寻找还未被充分开发的蓝海领域,对于内容创作者来说,…

思科模拟器--2.静态路由和默认路由配置24.5.15

首先,创建三个路由器和两个个人电脑。 接着,配置两台电脑的IP,子网掩码和默认网关 对Router 0,进行以下命令: 对Router进行以下命令: 对Router2进行以下命令: 本实验完成。 验证:PC…

MT3036 第一节离数课后

思路: 这道题与之前的表达式求值题目不同的是,有not这个单目运算符。而且如果表达式错误,要输入error。 把true和false成为操作数,把and or not成为运算符。 考虑error的情况: 1.and 和 or是双目运算符&#xff0c…

线性模型之岭回归的用法

实战:使用岭回归模型 完整代码: import numpy as np import matplotlib.pyplot as plt from sklearn.linear_model import LinearRegression from sklearn.datasets import make_regression from sklearn.model_selection import train_test_split fro…

pytest教程-46-钩子函数-pytest_sessionstart

领取资料,咨询答疑,请➕wei: June__Go 上一小节我们学习了pytest_report_testitemFinished钩子函数的使用方法,本小节我们讲解一下pytest_sessionstart钩子函数的使用方法。 pytest_sessionstart 是 Pytest 提供的一个钩子函数&#xff0c…

实战+代码!Selenium + Phantom JS爬取天天基金数据

功能: 通过程序实现从基金列表页,获取指定页数内所有基金的近一周收益率以及每支基金的详情页链接。再进入每支基金的详情页获取其余的基金信息,将所有获取到的基金详细信息按近6月收益率倒序排列写入一个Excel表格。 思路: 1.…

fastadmin对登录token的处理

fastadmin对token的操作 最近开发遇到一个场景,需要绕过验证获取登录,所以恶补了一下这个知识点,这个主要就是控制fastadmin的token的问题 代码分步实现 class Xcxuser extends Api {//关于鉴权protected $noNeedLogin [login,getopenid,…

错误: 找不到或无法加载主类问题(已解决)

今天在虚拟机中安装了idea2023.2的版本,运行代码时发现错误找不到主类! 直接说结论: 我先clean了一下target,然后重新build,发现maven报错了,idea2023.2默认使用了内置的maven,然后我切换了一下…