OpenClaw 网关自愈实战:systemd + 钉钉/飞书通知(零额外配置)

内容管家 编程开发 AI领域评论9字数 1673阅读5分34秒阅读模式

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。


三、前置条件

  • 已安装 OpenClaw,并完成钉钉、飞书通道对接(`channels.dingtalk`、`channels.feishu` 已配置)。
  • 至少有一个飞书群在 `groupAllowFrom` 中,且机器人已在该群;钉钉至少有一个群与机器人有过会话(以便从 sessions 中拿到群 ID)。
  • 系统为 Linux,使用 systemd(如 CentOS、OpenCloudOS、Ubuntu 等)。

  • 四、第一步:用 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
    

    说明:

  • `Environment=PATH=...`:保证 systemd 环境下能找到 `openclaw` 和 `node`。
  • `EnvironmentFile=-...`:可选,若存在则加载(如网关 token 等),前面的 `-` 表示文件不存在不报错。
  • `OnFailure=openclaw-fix.service`:本服务进入 failed 状态时,会触发自愈服务。
  • 执行:

    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 示例)

  • 读取 `openclaw.json` 和 sessions 文件路径时,可使用环境变量(如 `OPENCLAW_CONFIG_PATH`、`OPENCLAW_SESSIONS_PATH`)便于不同部署复用。
  • 飞书:`POST https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id`,body 中 `receive_id`、`content`(JSON 字符串,如 `{"text":"..."}`)、`msg_type: "text"`。
  • 钉钉:先 `POST https://api.dingtalk.com/v1.0/oauth2/accessToken` 拿 token,再 `POST https://api.dingtalk.com/v1.0/robot/groupMessages/send`,body 中 `robotCode`、`openConversationId`、`msgKey`(如 `sampleMarkdown`)、`msgParam`(JSON 字符串),header 中 `x-acs-dingtalk-access-token`。

  • 七、可选:DingTalk 扩展防崩补丁

    若日志中反复出现「WebSocket is not open: readyState 0」或「Ping Pong does not transfer heartbeat」导致进程退出,可在扩展依赖的 `dingtalk-stream` 的 `client.cjs` 中做最小改动(仅作防护,不改变业务逻辑):

  • 在心跳定时器回调里,仅当 `this.socket.readyState === 1`(OPEN)时才调用 `ping()` 或 `terminate()`,避免在 CONNECTING 状态下调用导致未捕获异常。
  • 在 WebSocket 的 `close` 事件里清除该定时器(`clearInterval`),避免重连后旧定时器仍对新的 socket 操作。
  • 修改前请备份原文件;扩展升级后可能被覆盖,需视情况重新应用或等待上游修复。


    八、常用命令与排查

  • 查看网关状态:`systemctl status openclaw-gateway.service -l`
  • 查看最近网关日志:`journalctl -u openclaw-gateway.service -n 200 --no-pager`
  • 自愈日志目录:建议将自愈脚本输出的日志统一写到 `~/.openclaw/workspace/logs/` 下带时间戳的文件,便于按时间排查。
  • 若从 PM2 迁移到 systemd:先 `pm2 stop openclaw` 并 `pm2 save`,再启用上述 systemd 服务,避免端口与进程冲突。

  • 九、小结

    通过「systemd 管理网关 + OnFailure 自愈服务 + 复用 OpenClaw 已有群聊 ID 的通知脚本」,可以在不增加新密钥、不写 webhook、不修改 openclaw 主配置结构的前提下,实现网关崩溃后的自动重启和钉钉/飞书群内自愈结果通知,适合长期挂机的 OpenClaw 部署。

     
    内容管家

    发表评论