Cron 健康面板:job 显示 ok,数据却没更新
我有三十多个 Hermes cron。有一段时间里,面板上大半是绿的,页面却偶尔空白。基金页没有当日净值,AI 日报 JSON 缺了 headlines,网关凌晨「失败」但进程明明起来了。
问题不在调度器本身。问题在:我一直把 last_status 当成健康。
这篇文章写 venxine.vip 上的 /cronstatus/ 怎么从作业清单变成健康面板。数据从哪读、假绿灯怎么拆、自杀式重启怎么降噪,以及产品文件要校验到什么粒度。
页面在 Demo 密码后:https://venxine.vip/cronstatus/
System 页也有一条迷你摘要。
1. 旧面板只回答了一个问题
最早的 cronstatus 很诚实,也很浅:
- 读
~/.hermes/cron/jobs.json - 按
last_status数 ok / error / paused - 表格列出名称、调度、上次运行时间
- footer 写「60 秒刷新」,JS 却只有 filter
它回答的是:「最近一次跑完,调度器记了什么。」
它不回答:
- 今天一共跑了几次、失败几次
- 一个每 10 分钟该跑的任务是不是已经 40 分钟没动静
- job 绿了,产物文件有没有今日业务键
- 那条 error 是真故障,还是机制噪音
在任务少的时候够用。任务过了 30 个,启用十七八条之后,扫表变成负担,绿点也开始骗人。
2. 健康要叠三层,不能只信 last_status
我最后落成三层。每一层解决上一层看不见的东西。
P0:今日态势 + 能展开的错误
页顶一条健康条,大意是:
今日 24 次运行 · 23 成功 · 0 失败
作业 14 正常 · 0 异常 · 0 过期 · 17 暂停
下次关键:基金涨跌预警 · 7m 后
同时补上:
next_run_at相对时间- 点击行展开
last_error/ delivery error - error、stale 置顶排序
- 真刷新:
fetch /api/cronstatus,60 秒一次,登录 cookie 带上
这一步之后,面板从「静态清单」变成「现在能不能睡」。
P1:读 executions.db,不要只看最近一次
Hermes 在 ~/.hermes/cron/executions.db 里有执行账本。字段大致是 job_id、status、started_at、finished_at、error。
有了它才能算:
| 指标 | 用途 |
|---|---|
| 今日 runs / ok / fail | 真正「今天」的态势 |
| 连续失败次数 | 比「上次 error」更有信号 |
| 平均 / 峰值耗时 | 抓 token 黑洞或卡住 |
| stale | 间隔任务超时未跑 |
stale 的启发式很土,但管用:从 cron 表达式估间隔,活跃窗口内若 now - last_run > max(2.5×interval, interval+5分钟) 就标过期。日更关键任务超过 36 小时没刷新也标。
注意:executions 里的 status 和 jobs.json 的 last_status 不一定同词。有 completed / failed / unknown。映射时要兼容,别只认 ok/error。
P2:产物心跳 + 业务校验
这是整篇里我最想强调的一层。
job 绿、文件 mtime 也是今天,仍然可能是假健康。典型例子:
daily-pl.json今天被 touch 过,但a.dates最新还是昨天- tracker 有当日文件,内容是空列表
- ainews 文件名是今天,headlines 只有 1 条
所以校验要进内容:
| 产物 | 业务条件(简化) |
|---|---|
| fund-tracker 当日快照 | 存在 YYYY-MM-DD.json,解析后非空 |
| daily-pl.json | 工作日 22:15 后应有今日 M/D;落后过多告警 |
| ainews JSON | 优先今日文件;headlines 不能过少 |
| daily-analysis | 最新日期键不能过旧 |
| cron ticker | 心跳文件不能太旧 |
盘中(工作日 9–15)tracker 或 ticker 挂了,顶部直接红条,不跟普通 warn 混。
告警文案尽量带建议动作,例如:
缺今日 7/24(最新 7/23)· 等22:00写入或23:45补漏
建议:等 daily-pl cron;仍缺则看补漏 job → /funddata/
绿点解决不了的问题,往往是「成功定义」写错了。成功不该是 exit 0,而该是「业务键在」。
3. 自杀式重启:error 不等于没重启
有一条 cron 天天 error,名字叫网关每日重启,脚本就两行意思:
systemctl --user restart hermes-gateway
04:30 跑它,等于让 job 去杀自己的宿主。结果:
- journal 里能看到 Stopping → Started,网关确实起来了
- jobs.json 的 last_status 仍是 error
- 错误文案类似:
Gateway shutdown (final-cleanup) killed the job's tool subprocess...
我查了 7/23、7/24 两天:大约 04:30 开始停,04:33–04:34 新进程起来。进程 uptime 也从凌晨算起。重启是成功的,记账失败。
处理方式我选了展示层降噪,没有停任务:
'c931a015fa63': {
'expected_noise': True,
'noise_patterns': [
'Gateway shutdown',
'final-cleanup',
'killed the job',
],
}
命中后:
- 徽章显示 NOISE,不是 ERR
- 不计入健康条的异常数
- 不进顶部告警列表
- 行变灰,可用「噪音」筛选
- 展开仍能看见原始 last_error
jobs.json 里的 error 真相保留。面板信噪比回来了。
也可以改成 systemd user timer 在 Hermes 外重启,彻底没有这条 job error。我暂时没改,因为「每天凌晨重启一次」这个意图还在,只是别让它污染基金采集的健康判断。
4. UI:核心四卡,下载类默认折叠
启用任务里,真正决定「今天钱和内容还在不在」的就那么几条:
- 📡 基金数据采集(盘中每 10 分钟)
- ⚠️ 基金涨跌预警
- 📋 每日收益数据(22:00)
- 🛡️ 每日数据一致性补漏(23:45)
面板顶部固定核心任务条,一眼扫完。
另一边是一堆暂停的「每周下载-*」。它们 last_status 很吵,日常又不相关。默认折叠,按钮可展开。否则 30 行表里一半是噪音行。
筛选也拆细了:不健康、过期、噪音、核心、采集、内容、运维。
「正常」不含 NOISE;「不健康」不含已降噪的网关 error。
5. 数据流(实现侧)
jobs.json ──► 作业元数据 / last_status / next_run
executions.db ──► 今日计数 / 连续失败 / 耗时
产物文件 mtime + JSON 内容 ──► 业务校验
│
▼
_cron_build_dashboard()
│
┌───────┴────────┐
▼ ▼
/cronstatus/ /api/cronstatus
(服务端渲染) (60s 前端刷新)
│
▼
/system/ Cron 健康迷你卡
权限:/cronstatus/ 和 /api/cronstatus 都挂在 Demo 密码前缀下,避免执行错误和路径信息裸奔。
关键代码位置(本站):
fund-web/app.py:_cron_build_dashboard、_cron_product_heartbeats、_cron_load_exec_statstemplates/cronstatus.html:健康条、核心条、表格、刷新- 网关脚本:
~/.hermes/scripts/gateway-daily-restart.sh
6. 几个坑
- footer 写了自动刷新却没写 setInterval,属于文案欺诈。要么实现,要么删文案。
- 只看 mtime 会把「空文件今日 touch」判绿。要进 JSON。
- 跨月 day-number 碰撞(6/2 vs 7/2)在别的页面害过人;日期键尽量用完整
M/D或 ISO。 - 自杀式任务不要跟行情任务共用「error = 坏了」的语义。要分开。
- 启用任务一多,没有核心分组就没有 30 秒扫一眼这回事。
7. 现在怎么用
盘中:看核心四卡 + 盘中红线。tracker 超过大约 25 分钟没更新就该紧张。
收盘后:盯 daily-pl 是否写入今日键;22:15 还没有就按建议去查 22:00 job 和 23:45 补漏。
凌晨:网关 NOISE 可以当背景音,别和采集故障一起报警。
System 页:只看今日成功/失败和异常数,细节仍回 cronstatus。
8. 和相邻系统的关系
这套面板不替代 cron 编排本身。编排、prompt、deliver 仍是 Hermes jobs.json 的事,我另有一篇写过调度侧。
它也不替代数据管线文章。fundtracker 从零搭建、三层防线、DCA 同源,说的是「数怎么来」。健康面板说的是「数还敢不敢信」。
账户侧的驾驶舱、真账草稿吃的是同一批 cron 产物。面板红了,那些页再好看也是旧戏重放。
收尾
我现在看 cron,第一眼不再数有多少绿点。
第一眼看:今天跑了几次、核心四条在不在、产物业务键在不在、那条红是不是又在自杀。
last_status 还在用,只是降级成其中一票,不是唯一票。
面板入口:https://venxine.vip/cronstatus/(Demo 密码)