☰
OpenClaw 服务守护实战:systemd 健康检查与分级自愈方案
2026/10/21 8:07:19 网站建设 项目流程

我跑 OpenClaw 也有一阵子了,从最早的好奇尝鲜,到后来被它“总挂”折腾到没脾气。这玩意儿本身很强大,能自己调度任务、调用工具、跑工作流,但代价就是进程真的不算稳。模型响应超时、临时目录文件堆积、内存被吃满、某个子进程卡死,各种姿势都能把它带走。白天挂了我还能忍,半夜挂了真是毫无办法。所以后来我下定决心,给它配了个“保镖”——一套自动健康检查加自愈守护机制,崩了自动拉起来,拉不起来就清理重来,再不行还能回滚配置并告警。现在已经连续跑了两周多,我基本就当它不存在,彻底解放了。

这篇文章就把我的整套方案写出来,适合正在跑 OpenClaw、或者跑任何类似 Node.js 常驻服务但被崩溃问题折磨的开发者和运维同学。内容包括健康检查脚本怎么写、为什么用 systemd 而不是简单挂个 crontab、分级自愈怎么设计,以及我踩过的几个坑。全程无废话,全是可复制的东西。

1. OpenClaw 为什么老挂:先搞清楚守护对象

1.1 崩溃形态远比“进程退出”复杂

先说现象。OpenClaw 挂掉并不是只有一种样子。我在最开始做守护方案时犯过的错,就是只盯着“进程还在不在”,结果闹出了不少乌龙。实际运行中它有这么几种死法:

  • 进程直接退出:这个最好理解,可能代码异常、可能 OOM、可能外部工具调用把整个进程带崩。ps一看进程没了,这种最好处理。
  • 进程活着但假死:这是最坑的一种。进程还在,端口也在监听,但所有请求都超时。通常是某个工作线程被阻塞住了,比如网络请求没有超时时间、某个浏览器自动化任务卡在页面加载上。这时候如果你只看进程,会觉得“一切正常”,但业务已经停了。
  • 日志停止更新:进程活着、端口也有响应,但实际上内部的消息循环已经停了,日志半天不写一行。这种比假死更隐蔽,我也是后面加了时间戳检测才发现的。
  • 内存无限膨胀:OpenClaw 长期跑着会持续积累内存,尤其是频繁调用模型接口、处理长上下文对话的场景。我的观察是,跑到 1.5GB 左右系统就开始 swap,再往上一点就可能 OOM 被内核杀掉。

所以“守护”这件事,第一步不是急着写重启脚本,而是先搞清楚你这个实例到底常以什么方式挂掉。我用了大概一周时间,每天看日志、记录现象,最终确认我这台的“主要死因”是假死和内存膨胀,进程直接退出的反而少。这直接影响了我后台的探活逻辑怎么写。

1.2 OpenClaw 崩溃的常见根因

聊几个我在日志和系统监控里看到的典型根因,给还没开始排查的同学一个参考方向:

  • 外部 API 耗时不可控:OpenClaw 要跟模型服务、网页内容、各种工具 API 打交道,外部服务一旦响应慢,工作线程就卡住,后续任务全部排队,看起来就像死了一样。
  • 子进程回收不及时:OpenClaw 会拉起浏览器、Shell 命令、脚本解释器等子进程。如果某些调用没有正确回收,子进程变成僵尸或残留,时间久了系统资源被大量占用。
  • 会话状态积压:长时间运行后,内存里的任务队列、历史上下文越堆越多,GC 来不及处理,整体性能下降,最终走向假死或 OOM。
  • 本地缓存文件膨胀:OpenClaw 的会话记录、临时文件都写在本地目录里。我遇到过一次某个临时目录积累了几万个小文件,文件系统 inode 耗尽,导致写日志都失败,整个进程行为开始变得诡异。

这些话不是玄学,你只要跑过长时间任务,基本都能遇到其中一两个。也正是因为这些根因,我才坚定了一个原则:守护脚本不能只是“重启进程”,它必须会做“判断是否真的健康”,以及“在重启无效时执行更深层的自愈动作”。

1.3 我给“健康”定的三条标准

经过一段时间的观察,我把“OpenClaw 健康”定义为三个条件,全部满足才算数:

  1. 进程存在:基础中的基础,进程没了必须拉起。
  2. 接口能快速响应:OpenClaw 本地有一个控制接口,我用它做 HTTP 健康探测。这里要注意,不是返回 200 就算好,还要求响应时间在合理范围内,否则就是假死。
  3. 日志时间戳是新鲜的:日志文件最后写入时间距现在不能超过 5 分钟,超过了说明内部循环可能已经停摆。

这三个层级缺一不可。只查进程,会漏掉假死;只查 HTTP,会漏掉日志停更;只查日志,又会在冷启动期间误判。把三者合起来,才算一个相对靠谱的“健康判断”。

2. 三种守护方案横评:为什么选择了“systemd + 健康检查”组合

2.1 方案一:crontab + ps + curl,看起来简单但问题很多

最容易想到的方案就是写一个 Shell 脚本,挂在 crontab 里每 5 分钟跑一次,发现进程不在就重启。我也试过,它的问题很明显:

  • 判断太粗:pgrep -f OpenClaw只能判断进程在不在,假死完全发现不了。
  • 重启太粗暴:每次都只做“杀掉再拉起”,如果问题是配置错了或者数据坏了,那就会陷入无限重启循环,像一匹脱缰的野马。
  • 没有状态记忆:crontab 脚本是无状态的,我不知道这个服务已经连续失败几次了,也不知道该升级处理还是该告警。
  • 5 分钟间隔太粗糙:OpenClaw 挂掉 5 分钟才发现,对于某些需要及时响应的场景已经太晚了。

当然,这个方案最大的好处是入门门槛极低,如果你只是想“偶尔挂了能自动拉起来”,它也能用。但离“7x24 小时不用管”差得远。

2.2 方案二:上进程管理器,比 crontab 强,但仍不够

有些人可能会想,那我用专业的进程守护工具,比如进程管理套件之类的。这类工具确实比 crontab 强,自带进程拉起、日志管理、Web 管理面板。但实际用下来,我发现它们对 OpenClaw 这种“进程活着但业务死了”的场景依然无能为力。

原因很简单:绝大多数进程守护工具的定位是“进程生命周期管理”,不是“业务健康判断”。它只知道“进程不在了要拉起来”,不会去问你那个接口,不会去看你的日志时间戳。要想做业务级健康检查,还是得自己写判断逻辑,然后告诉守护工具“该重启了”。

另外,如果你部署 OpenClaw 的机器上已经有 systemd 环境,再额外引入一个进程管理器,等于多养一个常驻守护进程,多一个出问题的点,我并不推荐。

2.3 方案三:systemd 服务单元 + 自定义健康检查脚本(最终选择)

系统自带的 systemd 其实是 Linux 上最好用的守护框架,根本不需要额外装东西。我的最终方案是:

  • 用systemd 服务单元来管理 OpenClaw 进程本身,设置崩溃自动重启、重启次数限制、开机自启。
  • 用systemd timer定期触发一个自定义健康检查脚本,这是“保镖”的核心大脑。
  • 健康检查脚本按我前面说三条标准探测,一旦发现异常,就执行修复动作:轻则重启服务,重则清理缓存、回滚配置,同时把状态写到文件里,实现“连续失败次数”的累计。

这套方案的好处是:探活逻辑完全在我自己手里,我想怎么判断就怎么判断;进程拉起交给 systemd 这个经过千锤百炼的组件,不用担心二次开发的稳定性;整个链路是“检查-判断-行动-反馈”闭环,有状态、有升级策略,比 crontab 那种一根筋强太多了。

2.4 三种方案对比

对比项crontab 脚本进程管理工具systemd + 健康检查脚本
判断进程存活支持支持支持
判断业务假死需自行实现不支持自行实现,可做多重判断
状态记忆无无用状态文件记录
连续失败升级处理无无可自定义升级策略
重启次数限制无有限支持 StartLimitIntervalSec
开机自启需另写支持支持
额外的守护进程开销无有无
可维护性差中高

3. 给 OpenClaw 写健康检查:别只看进程在不在

3.1 探活脚本的具体实现

这是我放在/opt/openclaw-guard/check_openclaw.sh的探活脚本,内容不复杂,但每一段都有它的用处。

#!/usr/bin/env bash # OpenClaw 健康检查探活脚本 # 返回 0 表示健康,非 0 表示异常(不同码段区分异常原因) OPENCLAW_PROC="openclaw" OPENCLAW_HTTP_URL="http://127.0.0.1:9876/health" OPENCLAW_LOG="/opt/openclaw/logs/openclaw.log" GUARD_LOG="/opt/openclaw-guard/guard.log" # 日志时间戳允许的最大滞后时间,单位秒 STALE_LIMIT=300 # HTTP 探活允许的超时时间,单位秒 CONNECT_TIMEOUT=5 MAX_TIME=10 log() { echo "$(date '+%F %T') $1" >> "$GUARD_LOG" } # 第一个检查:进程是否存在 if ! pgrep -f "$OPENCLAW_PROC" > /dev/null 2>&1; then log "FAIL process not found: $OPENCLAW_PROC" exit 1 fi # 第二个检查:HTTP 探活。这里必须设置超时,否则脚本自己会卡死 HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \ --connect-timeout "$CONNECT_TIMEOUT" \ --max-time "$MAX_TIME" \ "$OPENCLAW_HTTP_URL" 2>/dev/null) if [ "$HTTP_CODE" != "200" ]; then log "FAIL http probe: code=$HTTP_CODE" exit 2 fi # 第三个检查:日志时间戳是否新鲜 if [ -f "$OPENCLAW_LOG" ]; then LAST_TS=$(stat -c %Y "$OPENCLAW_LOG") NOW_TS=$(date +%s) DIFF=$(( NOW_TS - LAST_TS )) if [ "$DIFF" -gt "$STALE_LIMIT" ]; then log "FAIL log stale: last_write=${DIFF}s ago" exit 3 fi else log "FAIL log file missing: $OPENCLAW_LOG" exit 4 fi log "OK http=$HTTP_CODE log_age=${DIFF:-unknown}s" exit 0

脚本逻辑很简单,但有几个地方我必须强调:

pgrep -f的匹配词要选准。我之前用pgrep -f "node.*openclaw",结果守护脚本自己的命令行里也带着这个关键词,导致误判“进程永远活着”。后来我把探活参数和脚本路径区分开,并且在匹配词里用了比较精确的进程特征。如果你在 debug 时发现“明明挂了却说活着”,多半就是匹配词自匹配了。

curl 必须设置超时。这个坑太经典了,没写--connect-timeout和--max-time的 curl 在极端网络情况下能挂一天,健康检查脚本自己先卡死,引发一连串连锁反应。

日志时间戳我用了stat -c %Y,取的是文件最后修改时间。注意,如果你的 OpenClaw 会滚动日志,你要保证OPENCLAW_LOG指向的是当前正在活跃写的那个文件,而不是几天前的历史归档。

3.2 探活间隔为什么选 30 秒

探活脚本本身执行一次很快,但触发的频率要讲究。我最初用 5 秒一次,后来发现没这个必要,还给系统增加了无意义的负载;用 5 分钟一次又太迟钝,故障恢复太慢。最终我用 systemd timer 让它每 30 秒跑一次。

30 秒这个值是综合了“恢复速度”和“避免误判”之后的结果。OpenClaw 冷启动需要一点时间,太频繁的探测会在服务还没起来时连续误报;间隔太久又达不到“自动修”的及时性。再加上我脚本里 STALE_LIMIT 设了 300 秒,配合 30 秒的探活周期,等于说最长 5 分半左右就能发现日志停更类故障。对我来说完全够用了。

3.3 systemd 定时器怎么配

探活脚本本身不会自己定时执行,我用一个 oneshot 服务和配套 timer 实现周期调度:

# /etc/systemd/system/openclaw-healthcheck.service [Unit] Description=OpenClaw Health Check [Service] Type=oneshot ExecStart=/opt/openclaw-guard/check_openclaw.sh
# /etc/systemd/system/openclaw-healthcheck.timer [Unit] Description=Run OpenClaw health check every 30s [Timer] OnBootSec=30 OnUnitActiveSec=30 AccuracySec=5 [Install] WantedBy=timers.target

这里有个细节:timer 通过OnUnitActiveSec=30实现每 30 秒跑一次,而不是用OnCalendar,因为OnUnitActiveSec是从上一次执行结束开始计时,不依赖固定的墙上时间,对短周期任务更友好。AccuracySec=5允许一定误差,避免 systemd 为了精确到秒而频繁打断系统。

启用方式:

sudo systemctl daemon-reload sudo systemctl enable --now openclaw-healthcheck.timer

之后你会看到一个每 30 秒醒来一次的探活任务。想看它的执行历史可以:

systemctl status openclaw-healthcheck.service journalctl -u openclaw-healthcheck.service -n 20

健康检查脚本发现异常后如何触发修复动作?这就涉及到自愈的编排逻辑了。

4. 分级自愈动作编排:从“慢重启”到“清场重建”

4.1 第一级:systemd 自己兜底,自动重启

先让 systemd 干它最擅长的事——进程崩溃拉起。OpenClaw 的 service 文件我这样配:

# /etc/systemd/system/openclaw.service [Unit] Description=OpenClaw Service After=network-online.target Wants=network-online.target [Service] Type=simple User=openclaw WorkingDirectory=/opt/openclaw ExecStart=/usr/bin/node index.js Restart=on-failure RestartSec=10 StartLimitIntervalSec=300 StartLimitBurst=3 [Install] WantedBy=multi-user.target

关键参数解释一下:

  • Restart=on-failure:进程非正常退出(退出码非 0、被信号杀死等)时自动重启。主动 stop 不会拉起。
  • RestartSec=10:重启之前等 10 秒,给系统一点喘息时间,也避免快速崩溃时 CPU 被打满。
  • StartLimitIntervalSec=300和StartLimitBurst=3:这俩是“重启风暴”的闸门。如果 300 秒内重启超过 3 次,systemd 会放弃继续拉起,进入 failed 状态。这个机制非常重要,没有它的话,一个配置写错的 OpenClaw 会让你的机器无限空转,日志像流水一样刷屏。

有了这层兜底,进程层面的崩溃基本不用我操心。但正如前面说的,OpenClaw 更多是假死和日志停更,这些 systemd 是看不出来的。这时候就需要我那套定时探活脚本把问题找出来,并触发“第二级”修复。

4.2 第二级:探活发现异常,执行重启并累计状态

我在探活脚本里做了个小设计:如果探活失败,并且失败的是假死/日志停更类问题(退出码 2 和 3),就由本次探活任务主动把 OpenClaw 重启掉。这样比我等 systemd 自动拉起更主动——因为进程还活着,systemd 根本不会拉起它。

具体实现是在探活脚本异常时,让 systemd 服务单元直接调用systemctl restart openclaw:

# /etc/systemd/system/openclaw-healthcheck.service(改进版) [Unit] Description=OpenClaw Health Check [Service] Type=oneshot ExecStart=/opt/openclaw-guard/check_openclaw.sh

为了让探活任务能重启服务,还需要在 systemd 里给这个服务单元加上操作权限。或者更简单的方式,在脚本里用sudo systemctl restart openclaw,给脚本对应的用户配置免密 sudo 规则。我是给root用户跑了探活任务,所以直接调 systemctl 没有权限问题。如果你不想用 root,可以这样配 sudo:

# /etc/sudoers.d/openclaw-guard openclaw ALL=(root) NOPASSWD: /usr/bin/systemctl restart openclaw

连续失败次数的累计,我用一个状态文件实现:/opt/openclaw-guard/state。每次探活失败,计数加 1;探活成功,计数清零。如果失败达到某个阈值,就执行升级动作:

STATE_FILE="/opt/openclaw-guard/state" FAIL_COUNT=$(cat "$STATE_FILE" 2>/dev/null || echo 0) FAIL_COUNT=$((FAIL_COUNT + 1)) echo "$FAIL_COUNT" > "$STATE_FILE" if [ "$FAIL_COUNT" -ge 3 ]; then # 第三级动作:清理缓存 sudo /opt/openclaw-guard/cleanup_openclaw.sh fi if [ "$FAIL_COUNT" -ge 6 ]; then # 第四级动作:回滚配置 sudo /opt/openclaw-guard/rollback_openclaw.sh fi # 无论哪一级,都要尝试重启 sudo systemctl restart openclaw

为什么用 3 次和 6 次作为阈值?因为探活是 30 秒一次,3 次失败大约对应“连续 90 秒不健康”,已经能排除偶发抖动;6 次失败是“连续 3 分钟不健康”,基本可以断定普通重启解决不了,需要更激进的手段。这个阈值你可以根据自己的容忍度调整,但思路是通用的——失败次数越多,修复动作越重,而不是每次都做同样的事。

4.3 第三级:清理缓存和临时文件

OpenClaw 跑久了会在数据目录里留下大量临时文件、会话快照和模型缓存碎片。很多“重启无效”的故障,本质就是这些脏数据又让服务回到了同样的坏状态。所以第三级动作我写了一个清理脚本,专门处理这些:

#!/usr/bin/env bash # /opt/openclaw-guard/cleanup_openclaw.sh # 清理 OpenClaw 的缓存和临时文件,保留核心数据 DATA_DIR="/opt/openclaw/data" TMP_DIR="/opt/openclaw/tmp" CACHE_DIR="/opt/openclaw/cache" # 清理超过 24 小时的临时文件 find "$TMP_DIR" -type f -mtime +1 -delete 2>/dev/null # 清空缓存目录,但保留目录本身 if [ -d "$CACHE_DIR" ]; then find "$CACHE_DIR" -mindepth 1 -maxdepth 1 -exec rm -rf {} + fi # 保留最近 5 个会话快照 cd "$DATA_DIR" 2>/dev/null || exit 0 ls -t session-* 2>/dev/null | tail -n +6 | xargs -r rm -rf

这里只清理临时和缓存数据,绝不动核心会话目录,否则用户数据丢了,自愈就变自残了。我建议你在自己的环境里,把“哪些目录能清、哪些目录绝不能碰”列一个清单,写死在脚本里。

4.4 第四级:回滚配置

清理完如果还是不行,那大概率是最近一次配置变更导致的问题。比如改了模型参数、更新了某个功能开关、换了工具链配置。这时候就需要把配置回滚到上一次可用的状态。

我的做法是:

  1. 每次 OpenClaw 正常启动后,自动备份一份配置:cp config.yaml config.yaml.bak。
  2. 回滚时把config.yaml.bak覆盖回config.yaml,然后重启服务。
# /opt/openclaw-guard/rollback_openclaw.sh CONFIG_DIR="/opt/openclaw" BACKUP_FILE="$CONFIG_DIR/config.yaml.bak" if [ -f "$BACKUP_FILE" ]; then cp "$BACKUP_FILE" "$CONFIG_DIR/config.yaml" echo "$(date '+%F %T') config rolled back" >> /opt/openclaw-guard/guard.log else echo "$(date '+%F %T') no backup config found" >> /opt/openclaw-guard/guard.log fi

这个动作是在“清理完缓存、重启三次以上仍失败”时才触发,所以不用太担心误回滚。真误伤了也有备份,配置文件被覆盖后还能再手动恢复。

4.5 告警通知:让“自动修”的结果也能被你看到

自愈做得再好,也不可能永远不翻车。我加了一道告警逻辑:连续失败次数达到 9 次以上,或者回滚后仍然无法恢复,就通过 Webhook 向群机器人发一条消息,把时间、失败原因、当前状态发出来。这样即使机器半夜挂掉,第二天早上你也能看到“昨晚发生了什么”。

# Webhook 通知函数,放在探活脚本尾部 notify_webhook() { local msg="OpenClaw 守护异常:$1" curl -s -o /dev/null \ --connect-timeout 5 \ --max-time 10 \ -H "Content-Type: application/json" \ -d "{\"msg\":\"$msg\"}" \ "${WEBHOOK_URL}" } if [ "$FAIL_COUNT" -ge 9 ]; then notify_webhook "连续失败 ${FAIL_COUNT} 次,已尝试清理缓存和回滚配置,请人工介入" fi

告警渠道用什么不重要,关键是有一个能让你注意到的出口。没写告警之前,守护系统再怎么自动修,我心里其实还是悬着的;写了告警之后,我反而彻底放手了,因为它真的能兜底。

5. 真实踩坑清单:守护脚本本身也是个坑源

5.1 重启风暴:Restart=on-failure 成了雪崩放大器

我有一次改错了 OpenClaw 的配置文件,导致它启动后 10 秒内必然崩溃。理论上 systemd 的Restart=on-failure会自动拉起,但没有StartLimitBurst限制的话,它就是无脑拉起、崩溃、再拉起。那台机器的日志在几分钟内写了几个 G,CPU 负载冲到几十。

后来我加了StartLimitIntervalSec=300和StartLimitBurst=3,systemd 会在 300 秒内重启超过 3 次时放弃治疗,标记为 failed。看起来很简单的配置,但很多人忽略。如果你现在就在配 systemd 守护服务,第一件事就是确认这两个参数有没有写。

5.2 curl 没设超时:健康检查脚本把自己卡死了

前面提过一次,但值得单独再说。我的健康检查脚本最开始是这样的:

HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "http://127.0.0.1:9876/health")

看起来没问题,但如果 OpenClaw 假死了,进程还在但端口已经不再响应,这个 curl 会一直等下去。等到 TCP 超时,默认可能是好几分钟,甚至更久。

结果是:30 秒的探活 timer 触发了检查,检查脚本卡住了,下一个周期又触发一次,又卡住。系统里堆积了十几个卡死的 curl 进程,OpenClaw 没先挂,我的守护脚本先挂了。

解决方式就是我在正式版里写的:

curl -s -o /dev/null -w "%{http_code}" \ --connect-timeout 5 \ --max-time 10 \ "http://127.0.0.1:9876/health"

连接超时 5 秒,总超时 10 秒,绝不无限等。

5.3 日志撑爆磁盘:自愈系统自己先被磁盘拖死

OpenClaw 本身会打日志,守护脚本也会打日志,systemd 还会记录 journal,三重日志叠加,磁盘很快就满了。磁盘满了以后,OpenClaw 写不了日志,行为变得极端诡异;我的守护脚本也写不了状态文件,连续失败计数都存不进去。

我的应对组合:

  • OpenClaw 端配置日志轮转,按大小切分,保留最近 7 天。
  • systemd 的 journald 限制体积:
# /etc/systemd/journald.conf SystemMaxUse=500M
  • 守护脚本日志也加轮转,或者直接只保留最近若干行。

这些看起来跟“守护”无关,但恰恰是你长时间无人值守时最容易翻车的点。磁盘管理不是可选项,是必须项。

5.4 假死窗口期:别在冷启动时误判

OpenClaw 重启后需要一段时间才能恢复正常服务,如果健康检查脚本在它还没完全起来时去探查,就会打出“FAIL http probe: code=000”,然后触发重启,让服务永远起不来。

我在脚本状态和探活频率上都做了缓冲:

  • 重启后给 90 秒“宽限窗口”,期间只检查进程是否存在,不检查接口和日志时间戳。
  • 日志时间戳的STALE_LIMIT=300也足够宽容,避免冷启动阶段误判。

实现方式是在状态文件里记录上一次重启时间,探活脚本先读一下,如果离上次重启不足 90 秒,就提前 return 0,不做严格判断。

if [ -f "$STATE_FILE" ]; then LAST_RESTART=$(grep 'RESTART' "$STATE_FILE" 2>/dev/null | awk '{print $2}') NOW_TS=$(date +%s) RESTART_DIFF=$((NOW_TS - LAST_RESTART)) if [ "$RESTART_DIFF" -lt 90 ]; then exit 0 fi fi

这个缓冲我踩了不少坑才加上。如果你不想加,大概率会在测试重启时把自己逼疯——明明重启了,探活却老说失败,又把服务杀了,循环往复。

5.5 多实例部署时端口和目录冲突

如果你在一台机器上跑多个 OpenClaw 实例,那探活脚本里的端口、日志路径、状态文件都要参数化。我一开始把路径写死,导致第二个实例的守护脚本去检查第一个实例的日志,误判一堆。

解决方案很简单:把实例标识作为脚本参数传入,或者每个实例建一个独立目录放配置和脚本。不要偷懒用全局变量,多实例下迟早踩雷。

6. 部署步骤验证与效果复盘

6.1 完整的部署步骤清单

说了这么多,我把我最后落地的完整步骤列在这里,照着走一遍就能用:

  1. 准备目录:创建/opt/openclaw-guard/,存放守护脚本和状态文件。
  2. 写探活脚本:check_openclaw.sh内容如上,替换成你自己的进程名、端口、日志路径。
  3. 写自愈脚本:cleanup_openclaw.sh和rollback_openclaw.sh,内容根据你的数据目录情况调整。
  4. 改 systemd 配置:确保openclaw.service里有Restart=on-failure、StartLimitIntervalSec=300、StartLimitBurst=3。
  5. 配置探活服务单元和 timer:参考前面的示例,systemctl daemon-reload,enable --now起 timer。
  6. 配置告警:在探活脚本尾部加 Webhook 通知。
  7. 把状态文件初始化:echo "0" > /opt/openclaw-guard/state。

6.2 如何验证这套机制真的有用

部署完成后不能直接撒手不管,必须做故障演练。我当时一口气测了三种崩溃场景:

  • 直接杀掉进程:kill -9主进程,systemd 应在 10 秒内自动拉起。
  • 制造假死:暂停主进程(kill -STOP),探活脚本应在 30 秒内发现 HTTP 超时,并执行重启。
  • 日志停更:手动把日志时间改成 10 分钟前(或者直接停止写入),脚本应在 30 秒内发现时间戳过期并重启。

我实际测试后发现,场景一和场景二基本都能在 1 分钟内恢复,场景三稍慢一点但也不会超过 2 分钟。系统恢复后,我再查告警日志,确认通知发出来了,整个闭环才算成立。

这里要提醒一句:做故障演练的时候,最好挑一个不重要的时间窗口,并且准备好人肉恢复手段。万一守护脚本本身有 bug,比如误判后反复重启,你得能手动停掉 timer 防止雪崩。我当时就在演练前写好了一个“一键停用守护”的命令:

sudo systemctl stop openclaw-healthcheck.timer

6.3 战果:真实现了 7x24 不用管

到现在这套守护方案已经稳定跑了半个多月。这段时间里,OpenClaw 实际被自动重启过 4 次,其中 2 次是假死,1 次是日志停更,还有 1 次是内存膨胀被系统 OOM。全部都是在我睡觉的时候发生的,第二天起来看告警记录,才知道“昨晚它又挂了一次但已经修好了”。

数据上最直观的变化是:以前我每天都要 ssh 上去看一眼、手动敲 restart,现在我已经连续两周多没手动动过它了。唯一需要做的,是每周花一点时间翻一下守护脚本的日志,确认自愈行为是合理的,而不是同一根因反复触发。

6.4 最后几句实在话

这套方案虽然好用,但它不是一个“装上就一劳永逸”的东西。它更像一个尽职的管家,能帮你处理 90% 的日常故障,但剩下 10% 的新毛病,还是需要你偶尔看一眼日志、根据实际情况调整探活逻辑和自愈动作。比如我这台机器最初并没有清理缓存的动作,是后来发现“重启服务已经解决不了问题”时才加的。

另外,如果你准备照着这篇文章做,请务必把脚本里的路径、进程名、端口改成你自己的。不要直接复制粘贴——复制粘贴一时爽,路径不对火葬场。等你把它跑起来了,再根据你机器的实际崩溃特征去调参,慢慢就会变成一套真正属于你自己的“保镖”系统。

就我个人体验而言,给 OpenClaw 配了“保镖”之后,最大收获不是省了多少手动重启的时间,而是心态彻底变了。以前它一挂我就紧张,现在它挂不挂我根本不关心——反正有人替我看孩子。这种感觉,才是“7x24 小时不用管”的真正含金量。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询