Files
hermes-skills/skills/legal/contract-pass-workflow/references/queue-runner-duplicate-bug-20260702.md
T

92 lines
4.1 KiB
Markdown

# 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`