定时任务卡死了别等超时:hermes cron cancel 能停掉正在跑的那一次


凌晨三点,你被手机震醒:一个每小时跑的采集任务,卡在某个已经挂掉的上游 API 上。它还在跑,还在等超时,还在往日志里刷同一行错误。你想让它停下,于是打开终端敲了 hermes cron pause——然后发现它根本没停,只是“下一小时不会再起新的了”。当前这一次还在那儿,一行一行烧你的 token。

这是 pause 和“停止”之间最容易混淆的差别:pause 管的是调度,不管正在执行的那一次。以前的选项只有两个:等它自己撞上超时,或者把任务删掉再重建。v0.22.6 补上了第三种:hermes cron cancel。

cancel 到底做了什么

hermes cron cancel <job_id_or_name>
hermes cron cancel <job_id_or_name> --reason "wedged on the staging API"

任务引用可以写十六进制 ID,也可以写名字(大小写不敏感)。名字不唯一时命令会拒绝执行并列出候选 ID,避免你停错任务。

调度不受影响:任务仍然启用,下一次触发照常发生。变的只是当前这一次运行。

按任务类型,停法不一样:

  • 脚本任务(--script,包括 no-agent 模式):整棵进程树被终止——先给脚本的进程组发 SIGTERM,宽限期后升级为 SIGKILL,后台派生的孙进程也在内。这和脚本超时走的是同一套清理逻辑,所以不会留下一个“看不见但还在跑”的尾巴。
  • agent 任务:正在飞的那一轮在下一个检查点被中断。

关键在于,它是一次“请求”,不是一次 kill:取消记录挂在这次运行的 execution id 上,运行在下一个取消检查点(脚本通常远小于一秒)读到它,然后结束,并写一条 cancelled 记录,带上你给的原因。所以事后 hermes cron runs <job_id> 看到的是“被取消,原因:卡在 staging API”,而不是一个没头没尾的超时或失败。

还有两个体验细节:被取消的运行不发失败通知,也不计入任务的失败连击(failure streak)。这点很重要——你主动停掉的东西,不应该让任务在监控面板上继续背锅。

四个入口,同一个停止

停止在飞的运行不只走命令行:

  • hermes cron cancel <job>(命令行)
  • POST /api/cron/jobs/{id}/cancel(HTTP)
  • agent 自己的 cronjob_manage 工具,action: "cancel"
  • 桌面端:有运行在飞的任务,头部会显示 Stop;点了之后先显示 Stopping…,等到 cancelled 记录落盘,弹出 Run cancelled 确认

删除任务也会停掉它的运行。 hermes cron remove(以及 dashboard / 桌面的删除、agent 的 remove 动作)会把在飞的运行一起取消,原因记为 “job removed while running”。之前的行为是让它在后台继续跑完、产出一个没人会看的结果——现在不会了。

如果任务当时根本没在跑,cancel 是一个明确告诉你“没东西可取消”的空操作;如果在运行已经结束之后才到达,什么也不会改变。

有一件事它做不到:回滚

这点必须说清楚:cancel 不能撤销运行已经产生的副作用。文件已经写出去的、API 已经调用的、消息已经发出去的,都留在原地。它只负责让这一次停下来,不负责把世界恢复原状。

还有一个边界:中断发生在“下一个检查点”。如果某个工具调用正好卡在一个不可中断的系统调用里,停下来的时间取决于那个调用什么时候返回。

配套的另一半:错过的那次怎么办

停掉一次运行之后,下一个问题马上来了——如果任务刚好在你停机维护期间该跑,回来之后它会补跑吗?

默认行为是“补跑一次”:gateway 恢复后,落在停机窗口里的那个时段只跑一次,不会按时段数量连续补好几次。也可以用全局开关关掉:

hermes config set cron.catch_up_missed false

单个任务可以覆盖全局设置(这也是 v0.22.6 新增的部分):

hermes cron create "0 7 * * 1-5" "Morning brief" --catch-up off   # 过期的早报没有价值,直接跳过
hermes cron edit <job> --catch-up on                              # 回来先跑一次

桌面端的任务编辑器里,这对应 Missed runs 的三个选项:用默认、回来跑一次、跳过。宽限窗口默认是任务周期的一半,夹在 2 分钟到 2 小时之间;--grace-minutes 可以按任务覆盖(0 表示永不补跑,最大 1440)。补跑触发时,hermes cron list 里会标 ⚠ late / ⚠ catch-up after missed fire,不会悄悄发生。

顺手该知道的区别:pause、cancel、全局暂停

三个命令经常被混用,其实分工很清楚:

  • hermes cron pause <job>:保留任务、停止调度,不影响正在跑的那次;
  • hermes cron cancel <job>:只管当前这一次运行,调度不动;
  • hermes pause(不带 cron):全局紧急停止,所有定时触发都不再启动,但已经在跑的运行不会被杀,恢复后补上欠下的工作量。

想系统搭一套靠谱的定时任务,可以看站内的 cron 自动化完整指南;如果你更常遇到“任务明明该跑却没跑”,cron doctor 那篇 讲的是诊断路径;而错过补跑窗口那篇 讲的是这次顺带提到的 grace minutes 细节。

以上命令与行为都属于 v0.22.6 这个 tag,升级即可使用。