对,先做 1+2 一起,而且要改变一个原则:
以后不要再让 healthcheck 或手动命令直接跑
hermes gateway run --replace。
统一交给systemd --user管,healthcheck 只负责systemctl --user restart hermes-gateway。
否则你现在这个崩溃链会一直复现:
手动 gateway --replace
↓
杀掉 healthcheck 拉起的 gateway
↓
healthcheck 又发现挂了
↓
再拉一个
↓
多个 --replace 互相杀
↓
Discord 偶发 timeout
↓
gateway 退出
↓
循环最推荐顺序
1. 先停掉所有 Hermes gateway
2. 建 systemd user service
3. healthcheck 改成只操作 systemd,不直接启动 gateway
4. 再做 Discord 连接状态检测也就是:
先 1 + 2
再 3一、先清理所有旧进程
在 WSL 里执行:
pkill -f "hermes gateway" 2>/dev/null || true
ps aux | grep "hermes gateway" | grep -v grep || echo "no gateway"二、确认 systemd 是否可用
ps -p 1 -o comm=如果输出是:
systemd就可以继续。
如果不是,编辑:
sudo nano /etc/wsl.conf写入:
[boot]
systemd=true然后在 Windows PowerShell 执行:
wsl --shutdown重新打开 WSL,再检查:
ps -p 1 -o comm=三、创建 Hermes gateway 的 systemd user service
先找 Hermes 路径:
command -v hermes假设输出是 ${HOME}/.local/bin/hermes 或类似路径。
然后创建 service:
mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/hermes-gateway.service <<'EOF'
[Unit]
Description=Hermes Gateway
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
WorkingDirectory=%h/.hermes/hermes-agent
EnvironmentFile=%h/.hermes/.env
ExecStart=/usr/bin/env bash -lc 'exec hermes gateway run'
Restart=always
RestartSec=10
KillSignal=SIGTERM
TimeoutStopSec=20
[Install]
WantedBy=default.target
EOF重点是这里:
ExecStart=/usr/bin/env bash -lc 'exec hermes gateway run'不要用:
hermes gateway run --replace因为现在 service 本身就是唯一控制者,不需要 --replace。
四、启动并设置自启
systemctl --user daemon-reload
systemctl --user enable --now hermes-gateway.service
systemctl --user status hermes-gateway.service看日志:
journalctl --user -u hermes-gateway.service -f五、把 healthcheck 改成带锁,并且只重启 service
新建:
nano ~/.hermes/healthcheck_gateway.sh写入:
#!/usr/bin/env bash
set -euo pipefail
LOCK_FILE="/tmp/hermes-gateway-healthcheck.lock"
LOG_FILE="$HOME/.hermes/healthcheck_gateway.log"
exec 9>"$LOCK_FILE"
if ! flock -n 9; then
echo "$(date '+%F %T') another healthcheck is running, exit" >> "$LOG_FILE"
exit 0
fi
echo "$(date '+%F %T') healthcheck start" >> "$LOG_FILE"
# 确保 env 加载
if [ -f "$HOME/.hermes/.env" ]; then
set -a
source "$HOME/.hermes/.env"
set +a
fi
# 只检查 systemd 里的 gateway,不再自己启动 gateway
if ! systemctl --user is-active --quiet hermes-gateway.service; then
echo "$(date '+%F %T') gateway inactive, restarting service" >> "$LOG_FILE"
systemctl --user restart hermes-gateway.service
exit 0
fi
echo "$(date '+%F %T') gateway service active" >> "$LOG_FILE"赋权:
chmod +x ~/.hermes/healthcheck_gateway.sh手动跑一次:
~/.hermes/healthcheck_gateway.sh
cat ~/.hermes/healthcheck_gateway.log六、检查是否还存在多实例
pgrep -af "hermes gateway"正常只应该看到一个 gateway 主进程。
如果看到两个以上,先杀干净再交给 systemd:
pkill -f "hermes gateway" 2>/dev/null || true
systemctl --user restart hermes-gateway.service
pgrep -af "hermes gateway"七、暂时不要做的事
先不要让 Hermes 自己执行这种命令:
hermes gateway run --replace也不要让 healthcheck 里写:
nohup hermes gateway run --replace &这是你这次多实例互杀的核心原因。
八、下一步再加 Discord 智能检测
等 systemd 稳定后,再让 healthcheck 检测日志里的 Discord 状态,例如:
journalctl --user -u hermes-gateway.service -n 100 --no-pager | grep -Ei "connected|ready|discord|gateway"如果日志里长期没有 ready / connected,再重启 service。
但第一阶段先别搞复杂,先保证:
gateway 只有一个
不会跟终端生命周期绑定
不会被 --replace 互相杀你现在最该做的是:systemd user service 接管 gateway,healthcheck 只能 restart service,不能直接 run gateway。
2026-10-09 Codex 审阅说明
这是单 profile 阶段的部署方案。当前可能有多个独立 profile 的 gateway,不能只因多个进程就判断重复;广泛 pkill -f 会影响所有匹配的 gateway。user network-online.target 不保证系统网络已可达;EnvironmentFile 采用 systemd 环境文件语法,与 source .env 的 shell 语法并不完全相同。user service 注销后能否持续取决于 user manager 生命周期/lingering 等条件,不能无条件承诺。本次未改 unit、reload 或重启。
核验依据:systemd KillMode 说明。