#!/bin/bash # 私域Agent 隧道守护:每 60 秒巡检一轮,谁挂拉谁。由 launchd 常驻调用(KeepAlive)。 # 日志: /tmp/yawan-guard.log ROOT="/Users/macclaw/Desktop/yawan-workbench" # launchd 守护进程没有交互式 shell 环境,主动读取生产配置。 if [ -f "$ROOT/.env.production" ]; then set -a . "$ROOT/.env.production" set +a fi BACKEND_OK() { curl -s -m 4 --noproxy '*' http://127.0.0.1:8010/api/health >/dev/null 2>&1; } CF_ALIVE() { pgrep -f 'cloudflared tunnel --url http://127.0.0.1:8010' >/dev/null 2>&1; } NGROK_ALIVE(){ pgrep -f 'ngrok http 8010' >/dev/null 2>&1; } WECHAT_ALIVE(){ lsof -tiTCP:8765 -sTCP:LISTEN >/dev/null 2>&1; } # ---- 后端 ---- if ! BACKEND_OK; then echo "[$(date '+%m-%d %H:%M:%S')] 后端挂了 → 拉起" pkill -9 -f 'uvicorn app.main:app' 2>/dev/null (cd "$ROOT/server" && nohup env YAWAN_ENV=prod .venv/bin/python -m uvicorn app.main:app --host 127.0.0.1 --port 8010 >/tmp/yawan-uvicorn.log 2>&1 &) sleep 5 fi # ---- cloudflared 主入口 ---- if ! CF_ALIVE; then echo "[$(date '+%m-%d %H:%M:%S')] cloudflared 挂了 → 拉起" pkill -9 -f 'cloudflared tunnel' 2>/dev/null nohup /opt/homebrew/bin/cloudflared tunnel --url http://127.0.0.1:8010 --protocol http2 --metrics 127.0.0.1:20241 >/tmp/yawan-cloudflared.log 2>&1 & sleep 6 CF=$(curl -s -m 5 --noproxy '*' http://127.0.0.1:20241/metrics 2>/dev/null | grep -o 'https://[a-z-]*\.trycloudflare\.com' | head -1) [ -n "$CF" ] && echo "[$(date '+%m-%d %H:%M:%S')] 新备用地址: $CF/admin" fi # ---- ngrok 应急(地址固定)---- if ! NGROK_ALIVE; then echo "[$(date '+%m-%d %H:%M:%S')] ngrok 挂了 → 拉起" pkill -9 -f 'ngrok http 8010' 2>/dev/null nohup /opt/homebrew/bin/ngrok http 8010 --host-header=localhost:8010 --log stdout >/tmp/yawan-ngrok.log 2>&1 & fi # ---- 微信 iLink sidecar ---- if ! WECHAT_ALIVE && [ -f "$ROOT/scripts/wechat_ilink_sidecar.mjs" ]; then echo "[$(date '+%m-%d %H:%M:%S')] 微信 iLink sidecar 挂了 → 拉起" (cd "$ROOT" && nohup /opt/homebrew/opt/node@22/bin/node scripts/wechat_ilink_sidecar.mjs /tmp/yawan-wechat-sidecar.log 2>&1 &) fi