跳转到内容
use-cases / on-call-shift-cron / hero
CRON · EXPIRES_AT · 通知

随班次自动过期的 on-call 升级

周一 POST 一条 cron 条目,把 expires_at 设为周五 09:00。这条任务在四天里每 30 分钟呼一次你的手机,班次一结束就自动删除。下一个 on-call POST 自己的。没有 PagerDuty 排班、没有共享调度器配置、没有日历提醒去关掉它。

阅读 cron 文档
use-cases / on-call-shift-cron / handoff

班次如何在不开会的情况下交接

一周里的三个时间点。cron 条目的存在和班次精确对齐——不重叠、不缺口、没有遗留的 crontab 行。

周一 09:00 → 周五 09:01expires_at 承担整个班次
周一 09:00

POST 这条条目

一条 curl,schedule 是 */30,command 指向 hoody-notifications/push/me,expires_at = 周五 09:00:00Z。服务器返回 id e7d3。

周一到周五

Ping 跟着你的手机走

四天里每 30 分钟这条条目运行一次,呼叫 hoody-notifications。只 ping 你的设备。团队频道保持安静。

周五 09:01

条目自己删除

在 09:00:00Z,cron 服务删除 e7d3。09:30 那一拍没有任何东西可以触发。下一个 on-call 已经 POST 了自己的。

每个 on-call 在班次开始时写一条 POST。expires_at 字段就是整套交接协议——cron 服务负责清理,精确到秒。

use-cases / on-call-shift-cron / mechanism

两条 curl——每个班次一次

整个轮值协议每周就两次 HTTP 调用。on-call 周一 POST,周五 GET 一下,看到条目已经没了。没有共享调度文件需要合并。

monday.sh · m.dossantos
POST · 条目
# monday 09:00 — i'm on call until friday 09:00
curl -X POST \
  https://oncall.containers.hoody.com/users/me/entries \
  -H "Content-Type: application/json" \
  -d '["schedule":"*/30 * * * *","command":"curl -fsS hoody-notifications/push/m.dossantos","comment":"on-call wk19","expires_at":"2026-05-08T09:00:00Z"]'

# response
HTTP/1.1 201 Created
{ "id":"e7d3", "expires_at":"2026-05-08T09:00:00Z", "enabled":true }
friday.sh · m.dossantos
GET · 审计
# friday 09:01 — the next on-call took over
curl GET https://oncall.containers.hoody.com/users/me/entries

HTTP/1.1 200 OK
[
  // my entry e7d3 is gone — it expired
  // at 09:00 sharp. j.okafor's new
  // entry took over at 09:00:30.
]
# no slack thread, no calendar reminder

整个流程没有共享调度服务参与。cron 条目归这位工程师所有;下一个 on-call 的设置不依赖前一个清理干净。

use-cases / on-call-shift-cron / powers

这种形态从你一周里拿走的三件事

一条自己掌控生命周期的 on-call 条目,能终结 PagerDuty 配置和日历提醒解决不了的三类错误。

路由

Ping 只走一台设备——你的

条目的 command 指向你个人的通知端点,所以升级在你值班期间只发到你的手机,仅此而已。凌晨 3 点不再误炸团队频道。

归属

没有共享配置可改,也不用合 PR

不存在大家都改的 escalation_policy.yaml。每个工程师拥有自己那条条目。两位不同时区的 on-call 不可能因为编辑同一个文件而冲突。

清理

交接写在数据里,而不是聊天里

周五 09:00 一过,你不用再问「等等,我是不是还在收呼叫?」条目已经没了。验证交接就是一次 GET,少返回一行而已。

use-cases / on-call-shift-cron / capacity

cron 服务的保证

数字来自 Hoody Cron API。是真实的限制,不是编出来的。

  1. 过期精度1 秒

    自动过期对照系统时钟运行。expires_at 为 09:00:00Z 的条目会在 cron tick 触发的同一分钟内被删除——没有 5 分钟的清理工延迟。

  2. 每条调度的字段数5

    标准 5 字段 cron 表达式,外加 @hourly / @daily / @weekly 宏。值班期间每 30 分钟触发一次就是 */30 * * * *。

  3. 隔离1 / 用户

    每个系统用户都有自己的 crontab。下一个 on-call 的条目存在他们自己的 /users/[name]/entries 下——绝不会碰到你的。

依据 Hoody Cron API 的限制:托管条目通过 JSON CRUD,带 UUID 和 expires_at;按用户提供原始 crontab 访问;按用户的 crontab 隔离是内建的。

use-cases / on-call-shift-cron / punchline

班次结束的同时,cron 条目也结束——自动地。

之前 · 那份轮值文件之后 · 一周两条 curl
过去的交接长这样改 oncall.yaml → PR → 合并 → 找人手动关掉四个人 · 一份共享文件 · 周五上午 11 点照样被 ping
现在的样子POST /entries [ expires_at: '2026-05-08T09:00:00Z' ]一个工程师 · 一条 curl · cron 服务负责清理
阅读 cron 文档
use-cases / on-call-shift-cron / replaces

它替代了什么

想做 on-call 轮值时常规会去找的那些工具。它们每个都向你收一份服务费、一份配置仓库和一套交接仪式。一条带 expires_at 的 cron 条目,只收你一次 POST。

  • PagerDuty 升级策略对一次 curl 到你手机的事,按席位收费
  • Opsgenie 排班轮值为决定本周谁挨呼叫,搬出一整套产品
  • 自建的 on-call 配置仓库大家都提 PR,没人真正拥有的共享 YAML
  • 「记得交接时关掉 cron」你设好之后忽略、然后周五又重设的日历提醒
  • 手动清理升级周五上午 11 点 Slack 里发——「有人能帮我退订一下吗」
  • VictorOps 轮值又一个调度服务,做的事一个 expires_at 字段就能搞定
use-cases / on-call-shift-cron / cta

别再周五早上手动关 crontab 行。周一设好 expires_at,然后忘掉它。

阅读 cron 文档
use-cases / on-call-shift-cron / related

阅读其他内容