wechat-viewer-watchdog.sh
3.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#!/data/data/com.termux/files/usr/bin/bash
# WeChat Viewer 看门狗 — 检查 Flask + Hermes Gateway + 微信 Watcher 是否存活
# 由 Hermes cron 每 5 分钟调用一次
export PATH=/data/data/com.termux/files/usr/bin:$PATH
FLASK_PORT=5001
APP_DIR=/data/data/com.termux/files/home/wechat-viewer
LOG=$APP_DIR/watchdog.log
HOME_DIR=/data/data/com.termux/files/home
# ── 1. Flask ──────────────────────────────────────
ALIVE=$(su -c "ss -tlnp" 2>/dev/null | grep -c ":$FLASK_PORT")
if [ "$ALIVE" -eq 0 ]; then
echo "[$(date)] Flask 不在线,重启中..." | tee -a "$LOG"
cd "$APP_DIR"
pkill -f 'python3 app.py' 2>/dev/null
sleep 1
fuser -k "$FLASK_PORT/tcp" 2>/dev/null
nohup python3 app.py > $APP_DIR/flask.log 2>&1 &
sleep 3
ALIVE2=$(su -c "ss -tlnp" 2>/dev/null | grep -c ":$FLASK_PORT")
if [ "$ALIVE2" -gt 0 ]; then
echo "[$(date)] Flask 重启成功" | tee -a "$LOG"
else
echo "[$(date)] Flask 重启失败!" | tee -a "$LOG"
fi
fi
# ── 2. Hermes Gateway ──────────────────────────────
GATEWAY_ALIVE=$(pgrep -f "hermes.*gateway" 2>/dev/null | wc -l)
if [ "$GATEWAY_ALIVE" -eq 0 ]; then
echo "[$(date)] Gateway 不在线,重启中..." | tee -a "$LOG"
nohup hermes gateway > /tmp/hermes-gateway.log 2>&1 &
sleep 3
GATEWAY_ALIVE2=$(pgrep -f "hermes.*gateway" 2>/dev/null | wc -l)
if [ "$GATEWAY_ALIVE2" -gt 0 ]; then
echo "[$(date)] Gateway 重启成功" | tee -a "$LOG"
else
echo "[$(date)] Gateway 重启失败!" | tee -a "$LOG"
fi
fi
# ── 3. Stuck Job Reaper ──────────────────────────
# 清理因 Flask 重启而孤儿化的 hermes_jobs
python3 "$APP_DIR/reap_stuck_jobs.py" >> "$LOG" 2>&1
# ── 4. Orphan Report Reaper ─────────────────────
# 清理因 Flask 重启丢回调而未入库的日报文件
python3 "$APP_DIR/reap_orphan_reports.py" >> "$LOG" 2>&1
# ── 5. 微信自动回复 Watcher ────────────────────────
# 监听微信 DB 变化,写入 incoming.jsonl 队列
# 单例保护:每次都先 pkill 清场再起一个,不能只信一次 ps|grep 的探测结果——
# 探测在系统过载时会漏检/超时返回空,若不清场会在卡死的旧实例上再叠一个,
# 雪球式堆积出几百个进程拖垮整机(2026-07-25 事故:堆到 877 个吃满内存+swap)。
REPLY_DIR=$HOME_DIR/.hermes/wechat_reply
WATCHER_COUNT=$(su -c 'ps -A' 2>/dev/null | grep -c '[w]echat_reply_watcher')
if [ "$WATCHER_COUNT" -ne 1 ]; then
echo "[$(date)] 微信 Watcher 存活数=$WATCHER_COUNT(期望 1),重置中..." | tee -a "$LOG"
su -c "pkill -f wechat_reply_watcher.py" 2>/dev/null
sleep 1
su -c "/data/data/com.termux/files/usr/bin/python3 $REPLY_DIR/wechat_reply_watcher.py >> $REPLY_DIR/watcher.log 2>&1 &"
sleep 2
WATCHER_COUNT2=$(su -c 'ps -A' 2>/dev/null | grep -c '[w]echat_reply_watcher')
if [ "$WATCHER_COUNT2" -eq 1 ]; then
echo "[$(date)] 微信 Watcher 重置成功" | tee -a "$LOG"
else
echo "[$(date)] 微信 Watcher 重置后存活数异常: $WATCHER_COUNT2" | tee -a "$LOG"
fi
fi
# ── 6. 微信自动回复 Orchestrator Drain ──────────────
# 消费 incoming.jsonl 队列,处理候选事件
ORCH_LOCK=$REPLY_DIR/orch.lock
# 清理超过 5 分钟的残留锁
if [ -f "$ORCH_LOCK" ]; then
LOCK_AGE=$(($(date +%s) - $(stat -c %Y "$ORCH_LOCK" 2>/dev/null || echo 0)))
if [ "$LOCK_AGE" -gt 300 ]; then
rm -f "$ORCH_LOCK"
fi
fi
su -c "/data/data/com.termux/files/usr/bin/python3 $REPLY_DIR/wechat_reply_orchestrator.py --drain >> $REPLY_DIR/orchestrator.log 2>&1"