2026-04-28 无头租用云 Mac(HK / JP / KR / SG / US)上的 OpenClaw、launchd KeepAlive、退出码、ThrottleInterval,以及重启 / 崩溃循环排障
多数生产级 OpenClaw 安装在 Mac mini M4 上只暴露 SSH,反向代理打在 127.0.0.1,JSON 日志可通过 结构化日志 tail。若网关进程由 launchd 管理,你终会遇到的失败模式往往不是「神秘的大模型癖好」,而是退出后极速重启——有时良性的(你让 launchd 始终运行),有时是灾难性的(配置错误、缺 PATH,或监听前即崩溃)。这份 2026-04-28 长文串联 上游 HTTP 压力与 Webhook 背压,落脚到本地进程监督:KeepAlive 与 ThrottleInterval如何交互;重启噪声下如何读 StandardError的首条失败;何时unload LaunchAgent以在交互 Shell 重现。环境与机密见 launchd 环境篇,升级与允许列表见 openclaw doctor + 白名单。
无头云 Mac 上,launchd 就是你的 init
与笔记本不同,没有用户盯着 Terminal 看 npm 或 openclaw gateway何时退出。稳妥模式:装到专用服务账户,日志进轮转文件,让 launchd 掌管生命周期。2026 年常见误判是把 macOS 与 Linux systemd一一映射:KeepAlive、RunAtLoad等功能强大但必须显式节流,否则能把 2 秒的拼写错误放大成每小时数千次 execve——塞满 ~/Library/Logs 与远程日志船运器。请把进程退出当作一等信号,而不是「又崩了 shrug」。
- 用户 LaunchAgents —
~/Library/LaunchAgents承载每用户常驻服务;多数 OpenClaw 为最小特权落在此处。 - 系统 LaunchDaemons — 需管理员写入、爆炸半径更大;除非真需要 root 上下文应避免。
KeepAlive:你打开的是哪一种?
Apple 对 KeepAlive的属性表可以是布尔,也可以是带条件原因(网络、路径等)的字典。布尔 true是大锤:无论因何退出都重启进程——适合预期 24/7 的网络守护进程,但错误用在一次性迁移。更细的:需网络或某路径存在。调试「为啥在重启?」时先读:是我要求 launchd 保活,还是应用自己退出且 exit ≠ crash?在 KeepAlive true世界中,干净的退出 0 仍会触发重启——正是包装脚本detach 子进程错误时你看到的行为。
ThrottleInterval对齐到秒,监督器就是大锤;若抖动无固定节奏,更怀疑未处理 Promise或端口争抢,而非模型本身。
StandardOut / StandardError 路径:用真文件
无头SSH会话不是 TTY;stdio 掉进「黑洞」就会丢掉崩溃前最初 200 ms。把 StandardOutPath与 StandardErrorPath指到服务用户可写的目录,用 macOS newsyslog或简单每日 cron轮转,绝不要依赖交互终端滚屏。若与 出站 TLS事故对照,同一时间戳对齐的 stdout、nginx访问与网关 JSON 切片,胜过一张炫技 Grafana。
ThrottleInterval:重启节流阀
ThrottleInterval是 launchd驱动重启时,退出后到允许再次拉起之间的最短等待秒数。初装排障可把 10设为平静日志;稳态若希望瞬态文件锁后快速自愈可用 1–2。搭配:launchctl print gui/$(id -u)/com.example.openclaw(用户域,按需改标签)读出状态与上次退出。在值守手册写明该数字:「若 Throttle=10,最坏约每 10s 一次重启」,好设定期望当有人问MTTR < 1 min针对软件却不针对基础设施时该怎么答。
openclaw doctor可能在 launchd 仍处崩溃循环时通过——doctor 是短时交互二进制,拥有完整登录环境——你的 plist 可能省略了 node或全局 npm前缀的 PATH。务必把 env | sort与 doctor 输出diff。
工单里真正会记录的退出码
| 退出 / 现象 | 常见 OpenClaw 起因 | 先做啥 |
|---|---|---|
1(泛型)+ stderr 一条栈 |
配置解析、缺 OPENCLAW_变量或错误 cwd |
在 SSH 中用同样 ProgramArguments跑,set -a; source your.env; set +a,见 机密模式。 |
2(误用)来自 shell 包装 |
选项解析或 Mac 路径引号 | 在包装里记录原始 argv,避免 glob;若要 arm64 确认 Node 未跑 Rosetta(见 SSH shell 配置)。 |
126 / 127 |
不可执行,或 plist PATH里找不到 node |
二进制写绝对路径;在服务上下文跑 which -a node。 |
| 信号 9 / Linux 常说 137 — macOS 常是硬 kill | OOM、人工 kill 或(少见)看门狗 — M4 上同时看 LLM 与网关内存 | 在 Console 看 memory pressure或按 提供商整形降并发。 |
崩溃循环排障:改模型前先问六个问题
- 端口被占?游离网关或僵尸监听会导致 bind 失败;见 nginx 反向代理与端口对齐。
- 这是循环里的 exit 0?包装若 exit 0 却未
exec进子进程,仍可能触发KeepAlive。 - stderr 每次一样吗?同一行确定性错误 → 配置;栈在变 → 竞态或网络抖动。
- 上次改了什么?绑 git tag 或
npmshrinkwrap;发布纪律文化对非 App Store 服务也有帮助。 - 上游 401 而重试永不停止?可能需要断路器而非更大
KeepAlive压力——429/503 见 LLM 限流。 - 给大锤节流了吗?若没有,第一反应常是先加
ThrottleInterval以便读日志,再做真正修复。
log stream --style compact --predicate 'process == "openclaw"',否则噪声会掩盖你需要的首行信号。
Plist 运维清单(可贴进 Confluence / Notion)
- Label — 唯一反向 DNS;同一
UID不要复用他人com.前缀。 - ProgramArguments[0] — 完整路径;别赌登录 Shell 惊喜。
- WorkingDirectory — 仓库根,配置相对路径与
openclaw doctor假设一致。 - EnvironmentVariables —
HOME、PATH、(若必需)NODE_OPTIONS— 与机密文档对齐。 - KeepAlive + ThrottleInterval — 不要在 stderr 很小又无轮转时同时设激进重启。
plutil -lint ~/Library/LaunchAgents/com.yourorg.openclaw.plist
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.yourorg.openclaw.plist
告警「新加坡 OpenClaw 挂了」时的七步
- 看边缘健康(nginx)— 502 对比 504 区分上游与网关;出站失败再查 DNS / TLS。
- 看 launchd 状态 —
launchctl print标签;读上次退出与节流窗口。 - 稳住日志 — 若仍抖动则调
ThrottleInterval。 - 在同一
UID、无 launchd下交互复现。 - 配置 diff与机密轮换双人评审。
- 前滚到已知良好
npm版本,而不是生产上神秘补丁。 - 事后 — 工单里一段:根因、检测缺口、防护(例如 1 分钟内非零退出告警)。
常见问题:launchd 与 OpenClaw 网关本体
| 问题 | 2026-04-28 答复 |
|---|---|
要把 ProcessType设成 Interactive 吗? |
服务器守护进程通常不要;Interactive 改调度优先级。除非 Apple 文档针对你的 macOS 版本与负载类别另有建议,否则用标准后台行为。 |
需要 caffeinate吗? |
数据中心 24/7 租用的 Mac mini M4通常在电源策略层已禁用睡眠;若是笔电式主机(非 MacXCode 场景),真正 bug 若是唤醒崩溃,也不该用 caffeinate「糊过去」。 |
为何 Apple Silicon Mac mini M4 仍在这本手册里
launchd的诚实度取决于底层硬件。裸金属 Mac mini M4(香港、东京、首尔、新加坡、美国,1–2 TB,CPU 调度可预期)让「我们是否因工具调用太多把网关 OOM?」成为可量化问题而不是感觉。对本地 ML 实验友好的 MPS 核心同样给结构化日志转发、反向代理与 OpenClaw 栈留出头 room,因此团队会把这些文章与 区域节点定价及 接入说明一起读,当他们已超出绑在单一人身上的笔记本规模时。