mcpField
R
rails-webhooks

rails-webhooks

github.com/marckohlbrugge开发73051 次安装20 周前更新
代码仓库

关于 rails-webhooks

rails-webhooks 是面向 Rails 开发者的 Webhook 架构与可靠性实践指南,涵盖发送、接收、安全和运维。重点说明持久化投递、故障分类及熔断设计。

主要功能

  1. 01基于 outbox 的持久化投递
  2. 02区分目标故障与代码异常
  3. 03失败计数与自动停用
  4. 04SSRF 防护与签名验证
  5. 05多目标适配与租户隔离
  6. 06投递记录清理与监控

适用场景

  1. 01设计可恢复的出站 Webhook
  2. 02排查投递失败并保留审计信息
  3. 03保护 Webhook 目标免受 SSRF 风险
  4. 04构建带熔断机制的管理界面

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/marckohlbrugge/37signals-skills --skill rails-webhooks

安装后在 Claude Code 中输入/rails-webhooks确认已加载。

详细介绍

Rails Webhooks

用于出站/入站 Webhook 的架构与可靠性设计。参考 Fizzy 的事件驱动 Webhook 流水线,并以 Campfire 更简单的 Bot Webhook 作为对照。

交付模型(outbox 模式)

  • 领域事件会加入一个分发作业队列;该作业会展开处理,为每个 Webhook 创建一条持久化的 Delivery 记录,每条记录都有一个状态枚举(pending in_progress completed errored — 通过 index_by(&:itself) 以字符串为后备值)。
  • 每条交付记录都会通过 after_create_commit :deliver_later 自动加入自己的发送作业队列——先持久化,再发送,确保状态能在崩溃和重试后保留。
  • 使用 ActiveJob::Continuable 确保展开处理可安全应对崩溃:通过游标遍历匹配的 Webhook(find_each(start: step.cursor) + step.advance!),这样批次中途崩溃后会从断点恢复,而不是重新开始。
  • 在交付记录中记录请求元数据(标头、负载)和响应(状态码、正文),以便审计和调试。限制存储/流式传输的响应正文大小(约 100KB),并累计字节数。
  • 使用专用的 webhooks 队列,避免响应缓慢的目标拖累其他工作。

失败分类(关键区别)

  • 目标端的预期失败(超时、TLS、DNS、连接被拒绝、HTTP 4xx/5xx):捕获异常,将交付状态标记为 completed,并记录符号错误(response: { error: :connection_timeout })。交付作业已运行;失败的是目标端。不要重试该作业。
  • 意外异常(我们的代码有 Bug):标记为 errored!,然后重新抛出异常,让 ActiveJob 重试。
  • 这种区分能确保重试行为、仪表板和逾期情况跟踪准确可信。

逾期熔断器

  • 跟踪每个 Webhook 的连续失败次数和 first_failure_at;连续失败达到 N 次且跨越最短时间窗口后自动停用(Fizzy:1 小时以上发生 10 次失败)。
  • 成功时重置计数器。
  • 在 UI 中显示未启用状态,并提供手动重新启用端点(resource :activation)。

安全基线

  • 将 Webhook URL 视为不可信输入;实施完整的 SSRF 防护(解析并验证 IP、屏蔽私有地址范围、固定 IP、对每次重定向重新验证——参见 rails-security-multitenancy)。
  • 在发送时重新验证目标,而不只是创建时验证。
  • 创建后目标 URL 不可更改——更新操作只允许修改名称/订阅。更改目标需要创建新的 Webhook(以及新的密钥)。
  • 对负载签名:使用 HMAC 签名标头和时间戳标头。
  • 在模型层限制可订阅的事件:normalizes :subscribed_actions, with: ->(v) { Array.wrap(v).map(&:to_s).uniq & PERMITTED_ACTIONS }。
  • Webhook 管理端点要求管理员级别的身份验证。

集成适配器

  • 一条交付流水线可以支持多种目标类型:按 URL 模式检测(for_slack?、for_campfire?),然后根据目标调整内容类型、负载格式(JSON/表单/HTML)和渲染模板。不要为每种集成分别复制交付代码。
  • 使用租户对应的 script_name 渲染负载 URL,确保负载中的链接正常工作。

入站 Webhook(接收)

  • 首先验证签名(采用类似 construct_event 的方式),然后从提供方的 API 重新获取规范状态,而不是信任负载内容或顺序。
  • 对于聊天 Bot 风格的回调:按内容类型限制响应行为(只有 text/plain/text/html 会成为回复),并防止循环——绝不由 Bot 自己的消息触发 Bot。

租户安全

  • Webhook 记录和交付查询必须限制在租户范围内。
  • 确保事件展开处理不会泄露跨租户数据。

运维规范

  • 按保留策略定期清理旧交付记录(例如每 4 小时对过期范围调用 delete_all)。
  • 在 Webhook 管理 UI 中显示交付状态/历史记录。
  • 输出有用的日志和指标,用于跟踪成功率、重试次数和延迟。

风险信号

  • 发送后不再跟进,且没有持久化的审计记录。
  • 将目标端故障与代码错误以相同方式重试。
  • Webhook 目标 URL 可变。
  • 没有熔断机制——持续向失效的端点发送请求。
  • 不受限制地读取目标端响应。
  • 创建或查找投递记录时没有按租户进行范围限定。
  • 对于高流量事件,没有背压机制或队列隔离。

评论

支持 Markdown