4.1 KiB
4.1 KiB
Queue-Runner / Watchdog 重复审查 Bug(2026-07-02 确诊)
症状
Doro 不断收到同一份合同的重复"审查完毕"通知。同一天内夏阳合同被审查交付2次,家庭医生签约合同被审查交付后又有一个 thread 在跑。
根因
contract-queue-watchdog(cron 3174518affda,每20分钟)与 contract-queue-runner.sh 的交互存在逻辑缺陷:
时间线
- Runner 启动,从 manifest.txt 读取待处理文件列表
- Runner 对文件A启动
uwf thread start+uwf thread exec --background - 背景 worker(node进程)开始跑 workflow,耗时 1-2 小时
- Runner 自身在
wait for worker PID循环中——但如果 runner 自己因某种原因退出(进程被杀、OOM、超时),只剩 worker 在跑 - 关键 bug:workflow 跑完后 deliverer 交付文件 + final_review 通知 Doro,但 runner 已经不在了——无法把文件从 queue/ 移入 done/
- 20分钟后 watchdog tick:发现
RUNNER_PID为空 +DONE_CNT < TOTAL+ 无活跃 worker → 重启 runner - 新 runner 读 manifest,发现文件还在 queue/(因为没被移到 done/)→ 再次启动 workflow → 重复审查 → 重复通知
更隐蔽的变体(本次实证)
即使 runner 没死,也会出问题:
- Runner 在等 worker exit,worker 正常完成 → runner 移文件到 done/ → 进入下一份
- 但 runner 处理完 manifest 所有文件后正常退出
- 新文件在 runner 退出后被追加到 manifest(如 auto_notify 追加)
- Watchdog 重启 runner → runner 从头读 manifest → 前面的文件已在 done/ 会被 SKIP
- 但如果某份文件在 queue/ 中仍然存在(不在 done/)→ 又跑一遍
为什么文件会在 queue/ 而不在 done/
- Runner 异常退出,文件从未被移到 done/
- 新追加的文件,上一轮 runner 没跑到就退出了
- 文件被 auto_notify 或手动操作重新放回 queue/(不太可能但理论上存在)
缺失的防线
Runner 的 SKIP 逻辑只有一层:
[ -e "$FILE" ] || { log "SKIP (not found / already done): $BASENAME"; continue; }
只看文件是否还在 queue/ 目录。完全不查 contract-tracker.json。
修复方案
在 runner 的 === START: 之前加 tracker 查重:
# === BEFORE START: check tracker for already-completed ===
if python3 -c "
import json, sys
t = json.load(open('$HOME/.hermes/data/contract-tracker.json'))
completed = [c['original_filename'] for c in t['contracts'] if c['status']=='completed']
sys.exit(0 if '$BASENAME' in completed else 1)
" 2>/dev/null; then
log "SKIP (already completed in tracker): $BASENAME"
mv "$FILE" "$QUEUE_DIR/done/"
continue
fi
止血操作(已执行)
- ✅ kill 了正在重复跑的 reviewer thread (06FJ5NPHT9XX63HW0WDKXV3ZSR) 的 worker
- ✅ kill 了 queue-runner 进程 (PID 1907973)
- ✅ 将所有已处理文件移入 done/(家庭医生签约、朱家角标识标牌、计划生育协议)
- ✅ 验证 done/ 数量 ≥ manifest 行数 → watchdog 不会再重启 runner
今天的重复统计
| 合同 | 正常审查 | 重复审查 | 影响 |
|---|---|---|---|
| 恭兴 | 05:00 (end) | 02:45被cancel了不算 | 无重复 |
| 肃言 | 06:25 (end) | — | 无重复 |
| 卫健委 | 07:28 (end) | — | 无重复 |
| 夏阳 | 08:42 (end) | 11:40 再跑一遍 (end) | ⚠️ 重复通知 |
| 家庭医生签约 | 12:38→19:21交付 | 19:40又重启→21:16重复交付 | ⚠️ 重复通知 |
Watchdog 今天重启 runner 的次数
今天 watchdog tick 64次,其中触发 runner 重启 41次(00:00-10:40每20分钟都重启一次!)。大多数重启只是空跑(文件都在 done/ 了),但恭兴和夏阳那两次重启时文件还没进 done/,导致重复审查。
相关组件
- Runner 脚本:
~/.hermes/skills/devops/uwf/scripts/contract-queue-runner.sh - Watchdog 脚本:
~/.hermes/scripts/contract-queue-watchdog.sh - Watchdog cron:
contract-queue-watchdog(job_id:3174518affda),每20分钟 - Queue 目录:
/tmp/contract-queue/(manifest.txt + done/) - Tracker:
~/.hermes/data/contract-tracker.json