为什么 gateway.run 总是自动重启?从一条 Hermes 日志看懂进程替换、CPU 占用与排查思路

很多人在运行 Hermes 类 Agent 或 Gateway 服务时,会遇到一个看起来很困惑的问题:

明明只启动了一次程序,为什么日志总在提示重启?
为什么 CPU 突然飙高?
gateway run --replace 到底做了什么?

本文基于一段真实日志输出,拆解问题发生的原因,并提供一套可以直接操作的排查路径。全文只基于已有对话内容展开,不额外引入外部信息。


问题是怎么出现的?

先看日志:

WARNING gateway.run: Shutdown diagnostic — other hermes processes running:
  dapen       1570 92.6  2.0  94260 83524 ?        Ss   20:12   0:01 /home/dapen/.hermes/hermes-agent/venv/bin/python -m hermes_cli.main gateway run --replace

不少人看到这里,第一反应是:

程序是不是崩了,所以一直自动重启?

但实际情况往往并不是这样。

从这段日志来看,更准确的描述是:

系统检测到已经存在另一个 Hermes Gateway 进程,于是触发了替换机制。

换句话说,问题的关键通常不是“自动重启”,而是:

多个 Hermes 进程之间发生了相互替换,或者守护程序在重复拉起进程。


先理解日志里到底发生了什么

先拆解这一行:

python -m hermes_cli.main gateway run --replace

这里最关键的是:

gateway run --replace

它说明:

  1. Gateway 被启动了;
  2. 启动时发现已有 Hermes 进程存在;
  3. 新进程尝试替换旧进程;
  4. 旧进程退出;
  5. 某些机制又重新拉起旧进程;
  6. 最终进入循环。

所以问题的核心不是:

“为什么会重启?”

而是:

“为什么会不断出现新旧进程互相替换?”


从日志看出什么异常?

先看完整的一段:

dapen 1570 92.6 2.0 94260 83524 ? Ss 20:12 0:01

这是一个典型的 ps aux 风格输出。

字段顺序固定:

USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND

对应关系如下:

字段 含义
USER dapen 当前用户
PID 1570 进程号
%CPU 92.6 CPU 占用率
%MEM 2.0 内存占用率
VSZ 94260 虚拟内存
RSS 83524 常驻内存
TTY ? 无终端
STAT Ss 进程状态
START 20:12 启动时间
TIME 0:01 已累计 CPU 时间
COMMAND python … 执行命令

很多人会问:

你怎么知道 CPU 是 92.6%?

因为:

92.6

对应的是:

%CPU

字段。

所以,这个进程已经占用了约 92.6% 的 CPU


为什么高 CPU 值值得警惕?

再看两个字段:

START 20:12
TIME 0:01

意味着:


  • 进程刚启动;

  • 累计运行时间很短;

  • 但 CPU 占用非常高。

这种现象通常意味着:

情况一:快速重启循环

进程不断:

启动 → 退出 → 启动 → 退出

于是系统持续消耗资源。


情况二:忙循环(Busy Loop)

程序没有真正工作,而是在不停检测:

是否已有进程?
是否替换?
是否退出?

形成一个高频循环。


情况三:Watchdog 拉起循环

外部监控程序不断:

发现进程退出
↓
重新拉起
↓
再次退出
↓
继续拉起

这种情况 CPU 通常也会迅速上升。


为什么会一直自动重启?

下面是几个最常见原因。


原因一:systemd 或守护程序反复拉起

这是最容易忽略的问题。

很多人以为:

我只是手动运行了一个命令。

但实际上系统可能已经在后台运行了一个守护服务。

例如:


  • systemd

  • supervisord

  • pm2

  • Docker restart policy

  • shell 循环脚本

这些工具会自动监控进程。

一旦发现退出:

退出
↓
重新启动

如果你的 Hermes 又用了:

gateway run --replace

事情就会变成:

新进程启动
↓
发现旧进程
↓
replace 杀掉旧进程
↓
systemd 发现旧进程被杀
↓
再次启动旧进程
↓
形成循环

最终表现为:

“怎么一直重启?”


如何检查是不是 systemd 导致?

执行:

systemctl --user status hermes

或者:

systemctl status hermes

如果看到相关服务在运行,就说明可能存在自动拉起机制。

还可以查看:

ps aux | grep hermes

确认是否有多个相关进程。


特别注意 Restart=always

如果配置里存在:

Restart=always

说明:

进程退出后一定会重新启动。

这种情况下,与 --replace 搭配,很容易出现无限替换。


原因二:你其实启动了多个 Gateway

很多人无意中做过这样的事情:

第一次启动:

gateway run

后来忘了,又开一个终端:

gateway run --replace

于是:

第一个进程在运行。

第二个进程启动时:

发现已有 Hermes
↓
执行 replace
↓
替换旧实例

然后旧实例可能又被外部机制拉起。

最终:

多个 Gateway 相互抢占。


如何确认是不是多实例?

执行:

pgrep -af hermes

如果看到多个:

gateway run
gateway run --replace

那基本可以确认:

是多实例问题。


原因三:PID 文件或 Socket 没清理

很多 CLI 工具会创建:


  • pid 文件

  • lock 文件

  • socket 文件

用于记录:

当前已有运行实例。

但如果程序异常退出:

这些文件可能残留。

于是 Hermes 会误以为:

“已经有进程在运行。”

然后不断触发 replace。


如何检查?

查看:

ls -la ~/.hermes

重点关注:

.pid
.lock
gateway.sock

之类文件。

如果确认没有实际运行进程,可以尝试清理。


如何清理?

先结束 Hermes:

pkill -f hermes

然后:

rm -rf ~/.hermes/tmp/*
rm -rf ~/.hermes/*.lock

最后重新启动。


原因四:Docker 自动重启

如果 Hermes 跑在容器里,也可能出现类似问题。

例如容器配置:

"RestartPolicy": {
  "Name": "always"
}

逻辑会变成:

replace 杀进程
↓
container exit
↓
Docker 自动拉起
↓
重复

表现出来就是:

“怎么一直自动重启?”


原因五:内部 Watchdog 导致循环

还有一种情况:

Hermes 本身带有监控机制。

可能存在:

父进程
↓
监控子进程
↓
子进程 replace 父进程
↓
父进程再次拉起

形成“双 watchdog”。

这类问题常见特征是:

进程树异常复杂。


如何检查进程树?

执行:

pstree -ap | grep hermes

如果看到类似:

hermes-agent
 └─python
    └─python -m hermes_cli.main gateway run --replace

甚至多层嵌套:

python
 └─python
     └─python

说明:

可能出现了内部监控循环。


为什么日志里 CPU 会这么高?

很多用户会注意到:

92.6% CPU

并怀疑:

是不是程序本身有 bug?

其实未必。

因为:

START 20:12
TIME 0:01

意味着:

进程启动很短时间,但 CPU 已经被大量消耗。

这通常是:

1. Restart Loop

不断启动:

启动 → 退出 → 启动

2. Fork Loop

不断创建新进程。


3. Watchdog Loop

监控程序互相拉起。


放任不管会怎样?

如果进入循环:

可能出现:

日志暴涨

日志不断输出:

other hermes processes running

文件句柄耗尽

频繁创建连接。


Socket 被占用

新进程无法绑定。


CPU 长时间高占用

机器明显变卡。


内存逐渐上涨

尤其是子进程没有及时回收时。


推荐的排查顺序

如果你遇到:

Hermes 总自动重启

建议按下面顺序检查。


第一步:看是否有多个进程

执行:

pgrep -af hermes

看是否出现多个实例。

重点观察:

gateway run
gateway run --replace

是否同时存在。


第二步:查看进程树

执行:

pstree -ap | grep hermes

确认:


  • 是否多层 Python;

  • 是否 watchdog 循环;

  • 是否嵌套启动。

第三步:检查 systemd

执行:

systemctl --user | grep hermes

查看:

是否存在后台服务。


第四步:查看 .hermes 目录

执行:

ls -la ~/.hermes

检查:


  • pid

  • lock

  • socket

是否异常残留。


一个最直接的解决方案

如果暂时不确定原因,可以先做一次“彻底清理”。

先结束所有 Hermes:

pkill -9 -f hermes

确认进程已经消失:

pgrep -af hermes

如果没有输出:

说明已清理完成。

然后只启动一次:

gateway run

注意:

先不要加 --replace

如果这样运行稳定:

说明问题大概率是:

多实例互相抢占。


一个容易忽略的误区

很多人会误以为:

--replace 是“更稳定”的启动方式。

但从日志行为来看:

它的作用更接近:

替换已有实例。

因此:

如果你已经确定没有旧实例:

直接:

gateway run

通常更容易排查问题。

而:

gateway run --replace

适合:

明确知道已有实例存在时使用。

否则容易让问题变复杂。


FAQ:关于 Hermes 自动重启的常见问题

为什么只启动一次,却一直提示重启?

因为:

很可能后台已经有 Hermes。

新实例检测到已有进程后,开始 replace。

于是看起来像“无限重启”。


为什么 CPU 会到 92.6%?

因为:

92.6

ps aux%CPU 字段。

结合:

START 20:12
TIME 0:01

说明:

短时间内 CPU 被大量占用。

常见原因是:


  • 重启循环;

  • watchdog 循环;

  • 多实例互抢。

gateway run --replace 会干什么?

作用是:

检测已有实例,并替换它。

不是简单启动。


如何确认是不是多个实例?

执行:

pgrep -af hermes

查看是否出现:

gateway run
gateway run --replace

多个进程。


如何实时看 CPU 占用?

可以执行:

top -p 1570

或:

htop

查看实时资源占用。


最简单的恢复方式是什么?

通常是:

先全部结束:

pkill -9 -f hermes

确认:

pgrep -af hermes

没有输出。

再只启动一次:

gateway run

并暂时不要使用:

--replace

观察是否稳定。


HowTo:快速排查 Hermes 自动重启

步骤 1:确认是否多实例

pgrep -af hermes

步骤 2:查看进程树

pstree -ap | grep hermes

步骤 3:检查后台服务

systemctl --user | grep hermes

步骤 4:检查 Hermes 文件

ls -la ~/.hermes

步骤 5:彻底清理

pkill -9 -f hermes

确认:

pgrep -af hermes

无输出。


步骤 6:只启动一次

gateway run

不要先用:

gateway run --replace