定时任务不执行,很多人第一反应就是怪 cron。其实我自己排下来,真正容易出问题的通常是 3 层:调度时间算错了、Heartbeat 没在工作、或者 delivery 根本没把结果投出去。
所以这篇我不讲泛泛而谈的“看看日志”,我直接把我现场最常用的排查顺序摊开。
先把“任务有没有跑”“什么时候跑”“跑完发到哪儿”三个问题拆开。
一、先把 3 层问题分开看
调度层:时间表达式、一次性时间、时区换算有没有写对。
执行层:Gateway 网关和 Heartbeat 有没有正常工作。
投递层:任务其实跑了,但结果没有送到你正在看的渠道。
二、我第一次排查会先用一次性任务试水
官方文档里提到,工具调用时 schedule.at 用 ISO 8601 时间,schedule.everyMs 用毫秒。我的习惯是先用一次性任务做最小验证,先证明链路是通的,再去折腾 cron 表达式。
{
"name": "MorningDigest",
"schedule": { "kind": "at", "at": "2026-04-02T01:00:00Z" },
"delivery": {
"mode": "announce",
"channel": "telegram",
"to": "@ops_daily",
"bestEffort": true
}
}如果这条一次性任务能跑,说明大方向没问题;这时候再去查 cron 和时区,效率会高很多。
我排得最顺手的顺序是:先做一次性验证,再看时区,再看 Heartbeat,最后看 delivery。
三、现场我会这样查
先确认机器当前时间和时区,别让“本地时间”和“任务时间”对不上。
再确认 Gateway 网关本身是不是活着,至少要保证 Heartbeat 在跑。
把任务先改成最近 5 分钟内的一次性执行,看它会不会真的触发。
如果任务触发了但你没收到消息,再去查 delivery.channel 和 delivery.to。
date
timedatectl
journalctl -u openclaw -f | rg 'cron|heartbeat|delivery'如果你不是 systemd 方式跑的,也可以把上面的 journalctl 换成容器日志或者你自己的运行日志。关键不是命令长什么样,而是要把 cron、heartbeat、delivery 这三个关键词分开看。
四、delivery 这层也很容易误导你
官方文档里专门写了隔离任务的 delivery.mode、delivery.channel、delivery.to 和 delivery.bestEffort。如果你省略了 channel 或 to,任务会回退到主会话最后一次回复的位置。
所以有一种特别常见的假象:任务其实执行成功了,只是它把结果发到别的地方去了。
五、最常见的几种现场表现
| 表现 | 我先看什么 | 怎么处理更快 |
|---|---|---|
完全没有任何任务运行 | Gateway 与 Heartbeat | 先确认服务本身活着,再排 cron。 |
一次性任务能跑,cron 不跑 | 时区与 cron 表达式 | 把执行时间换成 UTC 再核一遍。 |
日志显示跑了,但没收到消息 | delivery 配置 | 优先看 |
偶发执行、偶发丢失 | bestEffort 和渠道侧限流 | 先收集日志,再决定是否让投递失败不阻断任务。 |











还没有评论,来说两句吧...