# Queue-Runner / Watchdog 重复审查 Bug(2026-07-02 确诊) ## 症状 Doro 不断收到同一份合同的重复"审查完毕"通知。同一天内夏阳合同被审查交付2次,家庭医生签约合同被审查交付后又有一个 thread 在跑。 ## 根因 `contract-queue-watchdog`(cron `3174518affda`,每20分钟)与 `contract-queue-runner.sh` 的交互存在逻辑缺陷: ### 时间线 1. Runner 启动,从 manifest.txt 读取待处理文件列表 2. Runner 对文件A启动 `uwf thread start` + `uwf thread exec --background` 3. 背景 worker(node进程)开始跑 workflow,耗时 1-2 小时 4. Runner 自身在 `wait for worker PID` 循环中——但如果 runner 自己因某种原因退出(进程被杀、OOM、超时),只剩 worker 在跑 5. **关键 bug**:workflow 跑完后 deliverer 交付文件 + final_review 通知 Doro,但 runner 已经不在了——无法把文件从 queue/ 移入 done/ 6. 20分钟后 watchdog tick:发现 `RUNNER_PID` 为空 + `DONE_CNT < TOTAL` + 无活跃 worker → **重启 runner** 7. 新 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/ 1. Runner 异常退出,文件从未被移到 done/ 2. 新追加的文件,上一轮 runner 没跑到就退出了 3. 文件被 auto_notify 或手动操作重新放回 queue/(不太可能但理论上存在) ## 缺失的防线 Runner 的 SKIP 逻辑只有一层: ```bash [ -e "$FILE" ] || { log "SKIP (not found / already done): $BASENAME"; continue; } ``` 只看文件是否还在 queue/ 目录。**完全不查 contract-tracker.json**。 ## 修复方案 在 runner 的 `=== START:` 之前加 tracker 查重: ```bash # === 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 ``` ## 止血操作(已执行) 1. ✅ kill 了正在重复跑的 reviewer thread (06FJ5NPHT9XX63HW0WDKXV3ZSR) 的 worker 2. ✅ kill 了 queue-runner 进程 (PID 1907973) 3. ✅ 将所有已处理文件移入 done/(家庭医生签约、朱家角标识标牌、计划生育协议) 4. ✅ 验证 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`