OpenClaw 网关自愈实战:systemd + 钉钉/飞书通知(零额外配置)
一、为什么需要自愈
OpenClaw 作为多通道 AI 网关,在 7×24 运行时会遇到进程异常退出、插件(如钉钉流式连接)偶发未捕获异常等情况。若无人值守,网关一旦挂掉,飞书/钉钉等通道就会断线。本文介绍如何用 systemd + 失败自愈服务 + 钉钉/飞书群通知 做一套「最小化自愈」方案,且完全复用 OpenClaw 已有配置,不新增密钥、不写 webhook,直接使用现有群聊 ID 发通知。
二、方案概览
网关进程:由 systemd 管理(`openclaw-gateway.service`),崩溃后自动 `Restart=on-failure`。
自愈服务:网关多次失败时,`OnFailure=openclaw-fix.service` 触发自愈脚本,收集日志、尝试重启并发送通知。
通知:从 OpenClaw 的 `openclaw.json` 和会话文件中读取**已有**的飞书群、钉钉群信息,向这些群发送自愈结果,无需在配置里新增任何 webhook 或 token。
三、前置条件
四、第一步:用 systemd 管理网关
4.1 启动脚本(建议独立成文件)
将网关启动逻辑放到一个脚本里,便于 systemd 调用并统一设置环境变量(如版本号,避免 Control UI 显示为 dev):
#!/usr/bin/env bash
# 建议路径:~/.openclaw/workspace/scripts/openclaw-gateway.sh
OPENCLAW_VERSION=$(node -p "try { require('/usr/local/node22/lib/node_modules/openclaw/package.json').version } catch(e) { 'dev' }" 2>/dev/null)
export OPENCLAW_VERSION
exec openclaw gateway run --port 19189
请根据本机 Node 与 openclaw 安装路径修改 `require(...)` 中的路径,并执行 `chmod +x openclaw-gateway.sh`。
4.2 systemd 服务单元
创建 `/etc/systemd/system/openclaw-gateway.service`(路径与端口请按需修改):
[Unit]
Description=OpenClaw Gateway (WebSocket + channels)
Documentation=https://docs.openclaw.ai
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=root
Environment=PATH=/usr/local/node22/bin:/usr/local/bin:/usr/bin:/bin
EnvironmentFile=-/root/.config/openclaw/gateway.env
ExecStart=/root/.openclaw/workspace/scripts/openclaw-gateway.sh
Restart=on-failure
RestartSec=10
OnFailure=openclaw-fix.service
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
说明:
执行:
sudo systemctl daemon-reload
sudo systemctl enable openclaw-gateway.service
sudo systemctl start openclaw-gateway.service
五、第二步:自愈服务与脚本
5.1 自愈 service
创建 `/etc/systemd/system/openclaw-fix.service`:
[Unit]
Description=OpenClaw Gateway 自愈:在网关反复失败时收集日志并尝试修复
After=network-online.target
[Service]
Type=oneshot
User=root
ExecStart=/root/.openclaw/workspace/scripts/openclaw-fix.sh
RemainAfterExit=no
[Install]
WantedBy=multi-user.target
无需 `enable`,由网关服务的 `OnFailure` 自动拉起。
5.2 自愈脚本逻辑概述
自愈脚本(如 `openclaw-fix.sh`)建议包含以下步骤(具体路径请按本机环境调整):
1. 收集日志:用 `journalctl -u openclaw-gateway.service -n 200` 以及(若存在)PM2 错误日志,写入带时间戳的日志文件,便于事后排查。
2. 检查 DingTalk 扩展:若使用了钉钉流式连接且曾出现「WebSocket is not open: readyState 0」导致进程退出,可检查扩展内 `dingtalk-stream` 的 `client.cjs` 是否已对心跳 `ping`/`terminate` 做防护(仅在 `readyState === 1` 时调用、或在 close 时清除 interval),仅记录结果,不自动改代码。
3. 重启网关:若当前由 systemd 管理,则执行 `systemctl restart openclaw-gateway.service`;否则可回退为 `pm2 restart openclaw`。
4. 发送通知:调用下方「通知脚本」,向 OpenClaw 已对接的钉钉群、飞书群发送一条自愈执行结果(主机名、时间等),无需在 `openclaw.json` 中新增任何配置项。
六、第三步:通知脚本——复用已有群聊 ID
核心原则:不新增 webhook、不写 token,只用 OpenClaw 里已经存在的群聊信息。
6.1 飞书
群 ID 来源:`openclaw.json` → `channels.feishu.groupAllowFrom`(数组),即已配置的允许接收消息的飞书群 chat_id(通常以 `oc_` 开头)。
鉴权:使用同文件中的 `channels.feishu.appId`、`channels.feishu.appSecret` 获取飞书 `tenant_access_token`,再调用飞书「发送消息」接口,向 `groupAllowFrom` 中的每个 chat_id 发一条文本消息即可。
6.2 钉钉
群 ID 来源:OpenClaw 的会话文件(如 `~/.openclaw/agents/main/sessions/sessions.json`)。遍历 key 为 `agent:main:dingtalk:group:*` 的会话,从会话对象的 `deliveryContext.to`、`lastTo` 或 `origin.to` 中取 openConversationId(即钉钉群会话 ID,通常以 `cid` 开头或为纯数字)。
鉴权:使用 `openclaw.json` 中 `channels.dingtalk.clientId`、`channels.dingtalk.clientSecret` 获取钉钉 access token,再调用钉钉机器人「群消息」接口,向上述 openConversationId 发送一条 Markdown 或文本消息。
这样,自愈通知会自动发到「当前 OpenClaw 已经在用的」飞书群和钉钉群,无需再配置任何新群或 webhook。
6.3 实现要点(Node 示例)
七、可选:DingTalk 扩展防崩补丁
若日志中反复出现「WebSocket is not open: readyState 0」或「Ping Pong does not transfer heartbeat」导致进程退出,可在扩展依赖的 `dingtalk-stream` 的 `client.cjs` 中做最小改动(仅作防护,不改变业务逻辑):
修改前请备份原文件;扩展升级后可能被覆盖,需视情况重新应用或等待上游修复。
八、常用命令与排查
九、小结
通过「systemd 管理网关 + OnFailure 自愈服务 + 复用 OpenClaw 已有群聊 ID 的通知脚本」,可以在不增加新密钥、不写 webhook、不修改 openclaw 主配置结构的前提下,实现网关崩溃后的自动重启和钉钉/飞书群内自愈结果通知,适合长期挂机的 OpenClaw 部署。


评论