[控场AI]
· 5 分钟阅读· 2,597 字

Cronhq:用 Postgres 锁保证「恰好执行一次」的定时任务调度器

Cronhq:用 Postgres 锁保证「恰好执行一次」的定时任务调度器

Cronhq 用 Postgres 锁和 Rust 构建开源定时任务调度器,解决传统 cron 重复执行与静默失败的痛点。

Cronhq 是一款基于 Rust 与 Postgres 构建的开源定时任务调度器,核心承诺是「恰好执行一次」。它通过 Postgres 的事务锁机制确保多实例部署时同一任务不会被并发触发,无需额外引入 Redis 或 ZooKeeper 等分布式锁中间件。配套能力涵盖带退避的自动重试、HMAC 签名的 Webhook 调用、针对外部任务的心跳监控,以及失败与恢复的双向告警。项目采用 MIT 许可证,支持自托管且与官方托管服务运行同一镜像,同时提供 5 个任务免费的 SaaS 方案。它主要面向有计费、结算等不容许重复或漏跑需求的生产环境团队。

定时任务(Cron Job)几乎是每个后端系统的标配,但它们的失败往往悄无声息。一个计费任务在两台服务器上各触发一次、导致重复扣款;一个任务某天挂掉,几周后才被人发现——这些场景对做过运维和后端的人来说并不陌生。开源工具 Cronhq 正是围绕这些痛点而生,它把「恰好执行一次」(exactly-once)作为核心承诺,试图解决传统 crontab 「静默失败」的老问题。

Cronhq: Cron jobs that actually run

传统 Cron 的三个隐形陷阱

原生 crontab 的问题不在于它不工作,而在于它「不告诉你何时不工作」。Cronhq 的介绍精准点出了几个典型场景。

第一个是重复执行。当你为了高可用在两台服务器上部署了相同的 crontab,同一个任务就可能被触发两次。对于发送邮件这类幂等操作影响有限,但对计费、扣款、结算这类任务,重复执行意味着直接的资金损失。

第二个是静默死亡。一个任务因为某次异常挂掉后,除非你主动监控,否则可能几周都无人察觉。原生 cron 不会主动告诉你「本该运行的任务没有运行」。

第三个是缺乏重试与告警机制。任务失败后既没有自动重试,也没有及时通知,问题往往在造成后果之后才被发现。

核心机制:用 Postgres 锁强制唯一执行

Cronhq 的技术选型有两个关键词:Rust 和 Postgres。它并没有采用「尽力而为」(best-effort)的调度策略,而是通过 Postgres 的锁机制来强制保证同一任务在同一时刻只被一个执行者拿到。

这个设计的意义在于,即便你出于容灾考虑运行了多个 Cronhq 实例,Postgres 层的锁也能确保任务不会被并发触发两次。相比在应用层做去重或依赖分布式锁中间件,直接复用数据库事务锁的方案更简洁,也更容易在自托管环境中落地——你不需要额外引入 Redis 或 ZooKeeper 之类的组件。

用 Rust 编写则带来运行时的稳定性与较低的资源占用,这对于一个需要长期常驻、可靠触发任务的调度器而言是合理的取舍。

Postgres 的锁机制在这里具体指的是咨询锁(Advisory Lock)或结合事务的行级锁(SELECT FOR UPDATE SKIP LOCKED)。后者是现代基于数据库的任务队列的通行方案:多个调度器实例同时尝试"认领"某条待执行的任务记录,数据库保证只有一个实例能成功获得行锁,其余实例的 SKIP LOCKED 子句会让它们直接跳过该行而非阻塞等待。整个"认领→执行→标记完成"流程包裹在同一个事务中,若执行器崩溃则事务回滚,任务回到可认领状态,从而同时具备了唯一性与故障恢复能力。这也是为什么说"直接复用数据库事务锁":它不依赖任何额外的原子操作原语,Postgres 本身的 ACID 保证已经足够。

围绕「可靠性」构建的配套能力

除了核心的执行保证,Cronhq 还提供了一整套围绕可靠性的功能:

  • 带退避的重试(retries with backoff):任务失败后按退避策略自动重试,而非一次失败就放弃。
  • HMAC 签名的 Webhook:触发外部服务时对请求进行签名,保证调用来源可信、防止伪造。
  • 心跳监控(heartbeat monitors):针对那些不由 Cronhq 直接运行、而是外部执行的任务,通过心跳检测它们是否按时「报到」,从而捕捉「本该运行却没运行」的情况。
  • 失败与恢复告警:告警在任务失败时触发一次,在恢复时再触发一次,避免告警风暴的同时又不遗漏状态变化。

这套组合拳的思路很清晰:不仅要让任务跑起来,还要让你随时知道它「跑没跑、跑成没成」。

HMAC(Hash-based Message Authentication Code)签名是一种基于共享密钥与哈希函数的消息认证机制。Cronhq 向外部 Webhook 端点发送请求时,会用预先约定的密钥对请求体生成签名并附在请求头中;接收方用同一密钥验证签名,从而确认请求确实来自 Cronhq 且内容未被篡改。这与 GitHub Webhooks、Stripe 事件通知等主流服务的做法一致。对于由定时任务触发的支付回调或数据同步接口而言,这层验证能有效防止恶意方伪造调度请求。心跳监控则是调度可观测性的另一个维度:对于在 Cronhq 体系之外独立运行的脚本或服务(如部署在其他机器上的 shell 脚本),它们在每次成功执行后主动 ping 一个 Cronhq 提供的 URL,若超过预设窗口期未收到 ping,即判定任务"静默缺席"并触发告警。

开源与自托管:跑的是同一个镜像

Cronhq 采用 MIT 许可证,完全开源且支持自托管。开发者 Michael Sunmisola 特别强调,自托管用户运行的是与官方托管服务完全相同的镜像——这一点对信任度很关键,意味着没有「阉割版开源」与「完整版商用」的割裂。

在商业模式上,Cronhq 提供免费额度:5 个任务免费,超出部分则走付费方案。这是典型的开源 + SaaS 双轨路线,既服务了愿意自己部署的团队,也照顾了希望开箱即用的用户。

在 Product Hunt 上,该产品获得了 78 个投票,位列当日榜单第 15 名,被归类于开源、SaaS 与开发者工具赛道。

谁适合用 Cronhq

如果你的业务里有涉及资金、结算、通知等不容许重复或漏跑的定时任务,Cronhq 的 exactly-once 保证正是它的核心卖点。对于已经在使用 Postgres 的团队而言,它的接入成本尤其低——无需额外引入调度中间件。

当然,对于只有寥寥几个幂等任务的小项目,原生 crontab 或云平台自带的调度器可能已经够用。Cronhq 真正的价值,体现在任务数量增长、可靠性要求提高、以及需要审计与告警的生产环境中。作为一个 MIT 开源、可自托管的方案,它至少提供了一个「可控且透明」的选择。

分享:

相关推荐