给Hermes装上心跳监控

起因:一个断了8小时没人报的管道

上午在搞 keynote.org.cn 的 AdSense 低价值内容问题,突然发现 review 子站的自动发布 cron 状态是 error。点进去看,base64 管道部署方式在 SSH 传输时断了——Broken pipe。

这个 cron 每 3 天跑一次,上次成功是 3 天前。也就是说,它可能已经断了整整一轮,而我完全不知情。更让我火大的是——之前设了"每日任务检查报告"(23:30 跑),理论上应该在当晚就发现。但它也静悄悄的,没报。

这就是问题:cron 断了,管家没吭声。

原来的"检查报告"为什么没用

之前的 每日任务检查报告(cron cbc01837af82)设计思路是:每天晚上 23:30,用 LLM agent 跑一遍 cron 状态列表,人工判断有没有异常,然后输出报告推微信。

三个致命缺陷:

说白了,它是一个"日报",不是"告警"。

重新设计:15 分钟一次的纯脚本心跳

我想要的很简单:

每 15 分钟扫一遍所有 cron,有新 error 立刻推微信,没 error 就闭嘴。同一个 error 不重复报。到晚上 23:30 自动出一份今日汇总。

不依赖 LLM,纯 Python 脚本,一次写入,cron 执行,零推理。

核心逻辑:

#!/usr/bin/env python3
"""Cron error watchdog — checks all Hermes cron jobs every 15 min.
   Silent when healthy, pushes WeChat on new errors.
   At ~23:30 outputs a daily summary."""

# 调重逻辑:track (job_id + last_run_at) 
# 同一个 job 的同一次运行只报一次
error_key = f"{job_id}_{last_run}"

if state.get(job_id) == error_key:
    already_reported += 1  # 已知错误,跳过
    continue

# 新错误 → 立刻组装消息
new_state[job_id] = error_key
error_messages.append(f"❌ [{name}] {scheduled} ...")

状态存 JSON 文件,跨运行持久化。每次扫描时对比上次记录的 error_key,相同的跳过,不同的推送。

日报模式:不额外占一个 cron 位

不单独建一个"每日汇总"cron。在同一个脚本里判断当前时间:

def is_daily_summary_time():
    """Current BJT hour is 23:20-23:45 → daily summary window."""
    now = datetime.now(BJT)
    return now.hour == 23 and 20 <= now.minute <= 45

正常跑的时候没 error → 静默(no_agent 模式下 stdout 为空 = silent)。但如果落在 23:20-23:45 这个窗口内 → 输出今日汇总(跑了几个 job、成功几个、失败几个)。

一个脚本、一个 cron、两个功能。删掉了旧的 每日任务检查报告,合并成一个。

怎么注册到 cron

脚本写完后,用 Hermes 的 cronjob 工具注册:

cronjob(action="add", name="Cron错误实时监控", 
        schedule="every 15m", script="cron_error_watchdog.py",
        no_agent=true, deliver="origin")

no_agent=true 是关键——纯脚本模式,不唤醒 LLM,直接执行。脚本的 stdout 就是推送内容,脚本静默就什么也不发。

跑一次验证:

$ python3 ~/.hermes/scripts/cron_error_watchdog.py
# 无输出 → 正常,没有新错误,也不是日报时间 ✅

其他顺手修的

借着这股劲,把今天发现的其他几个坑也填了:

收尾

这个监控脚本上线后,Hermes 的运维体系从"日报"升级到了"心跳"。15 分钟一次,比人盯着靠谱。

回头想想,之前太依赖 LLM agent 做运维判断了——让 AI 去"理解"cron 状态本身就是个错误的抽象层。该用脚本的地方就用脚本,杀鸡不用牛刀。