xiaowei-system/skills/cron-ops/SKILL.md

184 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: cron-ops
version: "1.0.1"
date: 2026-09-10
description: "Use when managing cron jobs or configuring fallback chains."
metadata:
version: "1.0.1"
author: "小唯"
category: "devops"
tags: ["cron", "fallback", "retry", "scheduled-tasks", "运维"]
---
# Cron 运维 Skill
Hermes 定时任务的配置、fallback、重试和故障排查。
## 配置结构
`~/.hermes/config.yaml` 中 cron 段:
```yaml
cron:
model: glm-4-flash # 主模型
model_provider: zhipu # 主 provider
fallback_model: agnes-2.5-flash # fallback 模型
fallback_provider: agnes # fallback provider
provider: auto # auto = 按 model_provider 走
gateway_required: true # gateway 在才 fire
wrap_response: true
```
**Fallback 链**: 主模型失败 → fallback_model → 全局 fallback_providersconfig.yaml 顶层)
## Job 配置
`~/.hermes/cron/jobs.json` 中每个 job
```json
{
"id": "5b108ad99991",
"name": "蒸馏模型看门狗",
"script": "distill-model-watchdog.py",
"no_agent": true,
"schedule": "every 30m",
"model": null,
"provider": null
}
```
**关键**: `model`/`provider` 为 null 时继承 cron 默认配置;设置具体值会覆盖全局 fallback。
## 两种模式
| 模式 | no_agent | 执行方式 | 适用场景 |
|------|----------|----------|----------|
| **脚本模式** | true | 直接执行脚本stdout 投递 | 看门狗、数据采集、健康检查 |
| **Agent 模式** | false | LLM 执行 prompt可用工具 | 分析、报告、需要推理的任务 |
## 脚本路径规则(重要 Pitfall
1. **必须用绝对路径**: `/home/muc/.hermes/scripts/xxx.sh`,不能 `~/.hermes/scripts/xxx.sh`
2. **不支持参数**: script 字段不能 `script.sh arg1 arg2`cron 系统会把整个字符串当文件路径
3. **脚本必须在 scripts 目录**: `~/.hermes/scripts/` 下,否则报 "Script not found"
4. **Python 脚本自动用 sys.executable**: `.py` 文件用当前 Python 解释器执行
5. **Shell 脚本自动用 bash**: `.sh`/`.bash` 文件用 `/bin/bash` 执行
## 投递目标deliver语义2026-09-05 实测)
| 值 | 实际去向 | 注意 |
|----|----------|------|
| `origin` | **创建该 job 时的 chat** | 在 DM 里创建 → 通知回私聊!不是自动去群 |
| `feishu`(裸值) | Home channel= 当前 profile 的 Home可能是 DM | 同样可能落私聊 |
| `local` | 仅存 `~/.hermes/cron/output/`,无消息投递 | watchdog 静默模式 |
| `feishu:<chat_id>` | 显式指定 chat | 群通知必须显式写群 ID |
- **⛔ 飞书 DM 的 chat_id 也以 `oc_` 开头**(如 `oc_cd14...`)——不能凭前缀判断私聊/群。判定靠 MEMORY 映射:群=`oc_81f6df701c872a1122f32080e366543f`;小唯↔牧尘 DM=`oc_cd14ec7518926e57d26c5e339ebba3b3`user `ou_f20eb15b3a76639fed35977c01ddcbb4`)。
- **⛔ 牧尘铁律:任务通知一律发群,不发私聊**。新建带通知的 cron 时 deliver 直接写 `feishu:oc_81f6df701c872a1122f32080e366543f`,别依赖 origin 默认。
- 检查存量:`jobs.json` 里 `deliver: origin` 或裸 `feishu` 的 job 若创建于 DM = 通知发私聊 → 逐个 update 为群 ID。
## Fallback 配置最佳实践
### Agent 模式 jobs
- 设置 `model: null`, `provider: null` → 继承 cron 默认
- 默认配置已有 fallback: zhipu → agnes
- 全局 fallback: mimo → deepseek → opencode-free
### 脚本模式 jobs
- 脚本内部实现重试逻辑Hermes 不自动重试脚本)
- 推荐模式:
```python
import subprocess, sys, time
def run_with_retry(cmd, max_retries=3, delay=5):
for i in range(max_retries):
result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
if result.returncode == 0:
print(result.stdout)
return 0
if i < max_retries - 1:
time.sleep(delay)
return result.returncode
if __name__ == "__main__":
sys.exit(run_with_retry([sys.executable, "target_script.py"]))
```
## 常用命令
```bash
# 列出所有 jobs
hermes cron list
# 手动触发
hermes cron run <job_id>
# 查看 job 详情
hermes cron show <job_id>
# 创建 job
hermes cron create "every 30m" --name "任务名" --script "script.py" --no-agent
# 暂停/恢复
hermes cron pause <job_id>
hermes cron resume <job_id>
```
## 故障排查
### Job 状态为 error
1. 检查 `last_fire_error` 字段
2. 脚本路径是否正确(绝对路径)
3. 脚本是否有执行权限
4. 手动执行脚本测试
5. **先验上游依赖是否运行**(非脚本问题占多数):
- llama-server cron → 查 `pgrep -fa llama-server``systemctl --user is-active llama-server-7b`
- 织忆 cron → 查 `curl -s http://127.0.0.1:7821/health`
- 股票 cron → 查网络/API key
- **41 次连续失败先看失败时间是否集中在某服务未启动的时间窗口**
### Fallback 不生效
1. 检查 job 的 `model`/`provider` 是否覆盖了全局
2. 确认 fallback_provider 的 API key 在 .env 中
3. 检查 fallback 模型是否可用
### 脚本静默失败
- no_agent 模式下,空 stdout = 静默(不投递)
- 检查脚本是否有输出
- 查看 journalctl --user -u hermes-gateway
### 飞书 TTS 静默失败
- MiMo quota 429 exhausted → 飞书 TTS 消息被吞不报错
- 验证:直接 curl MiMo TTS 端点看是否返回 quota error
- 备选:切 edge-tts内置无 quota 限制)
## Pitfalls
1. **不要覆盖 job 级 model/provider**: 除非特殊需求,让 job 继承 cron 默认配置
2. **脚本重试在脚本内部实现**: Hermes 不自动重试 no_agent 脚本
3. **绝对路径**: 所有脚本路径必须是绝对路径
4. **不支持参数**: 脚本不能带参数,需要参数时写 wrapper 脚本
### 模式 8 复发实例 + 全库扫描根治2026-09-05
同一天两个 no_agent 看门狗踩同一坑(各自脚本带 `--apply` 被当文件名):
- `backup-cleanup.py --apply`(备份自动清理 6a87615b5155→ Script not found → 备份清理停摆数天
- `resource-watchdog.py --apply`(文件资源看门狗 c336c1c3b39f→ 同上
**根治修复模板**wrapper 放 ~/.hermes/scripts/chmod +x`hermes cron edit <id> --script <wrapper>`
```bash
#!/bin/bash
# <name> cron wrapper参数放这里
exec python3 /home/muc/.hermes/scripts/<script>.py --apply
```
**全库扫描根治检查**(新建/修改 no_agent job 后必跑):
```bash
python3 -c "import json; d=json.load(open('/home/muc/.hermes/cron/jobs.json')); jobs=d.get('jobs',d) if isinstance(d,dict) else d; items=jobs if isinstance(jobs,list) else list(jobs.values()); [print('❌', j['id'][:12], j.get('name'), repr(j.get('script'))) for j in items if j.get('script') and ' ' in str(j.get('script'))]"
# 无输出 = 全部干净;有 ❌ = 还有带参 script 待修
```
**症状识别**cron 输出 "Script not found: /path/to/xxx.py --apply"(把参数拼进路径找)→ 100% 模式 8。修复后 `hermes cron run <id>` 验证 succeeded。
5. **状态文件保护**: 脚本的状态文件(如 rsshub_ai_seen.json要防并发写入