运维熟悉OpenClaw网关顺畅路径上的日志,但生产环境会教会你退出码这门词汇。在2026 年,无论你是在工作室 Mac mini 上自建还是租用云端实例,macOS launchd 包裹 Node 运行时方式一致:137 多半暗示内存压力,143 常常是一次礼貌的SIGTERM(例如重载),而快速 respawn 往往指向 plist 配置而非模型质量。本文把代码映射到信号、演示如何在统一日志里过滤而不淹没在噪声里、把症状关联回 doctor 网关诊断,并说明在扩大并发之前何时该先抓 Activity Monitor 样本。
请搭配 LaunchAgent 重启与恢复模式 做干净重启,以及在对话与工具输出无限膨胀时阅读 内存与上下文裁剪。
退出码速查
| 码 | 常见含义 | 首要检查 |
|---|---|---|
| 0 | 干净退出 | 区分有意停止与看门狗 |
| 1 | 通用 Node 错误 | 读 stderr 路径;前台重跑 |
| 137 | OOM / SIGKILL | 内存压力、工具输出体量、模型上下文 |
| 143 | SIGTERM | launchd 重载、手动 kill、部署脚本 |
macOS 也会为图形应用 surface Jetsam 事件;守护进程则更多在统一日志里留下原因字符串——牢记网关 bundle id 的拼写,谓词才能保持狭窄。
在多人共用一台云端 Mac mini 时,还要区分哪个用户域加载了 LaunchAgent:launchctl print gui/$UID/... 与 bootstrap 域输出不一致时,看到的退出码可能来自“你以为已卸载”的旧标签。
ThrottleInterval 与崩溃循环
作业以非零退出时,launchd 会退避。若 plist 把 KeepAlive 配得很激进而进程在一秒内崩溃,运维会看到一堵相同时间戳的墙,掩盖第一条真正的错误行。调试期间可暂时把 ThrottleInterval 提到10 秒,修好根因后再收紧以换取生产响应速度。
文档化 RunAtLoad 是否为 true:常见误报发生在工程师工作时间手动 unload 了代理,但自动化几分钟后又 reload,掩盖真实触发条件。
若网关由 CI 频繁替换二进制,观察连续重载是否让 ThrottleInterval 一直生效——这时 Console 里会看到 launchd 以固定间隔尝试拉起,容易误判为“内存泄漏”而非配置抖动。
可读的 log show 谓词
log show --last 30m --predicate \
'subsystem == "com.apple.xpc.launchd" AND eventMessage CONTAINS[c] "openclaw"'
可再用 process == "launchd" 叠加你的标签字符串。导出 JSON 方便审计方在不登录 SSH 的情况下 grep。
对长时间故障,把窗口扩到 --last 24h 并重定向到文件;统一日志体积大,务必在笔记本冷却后再打开,以免活动监视器本身抢焦点。
Console.app 工作流
- 创建名为“网关退出”的收藏,组合子系统与消息包含过滤器。
- 复现前先开始流式读取;崩溃后立即暂停以免缓冲区滚动丢失。
- 仅在怀疑文件系统或内核扩展时再附加 sysdiagnose——否则保持证据轻量。
内存压力与工具扇出
退出 137 常与并行工具调用有关——每次调用都可能缓冲数 MB 的 stdout。当主机只有8 GB统一内存时,把并发工具限制在三个以下,或把模型上下文窗口降到你在活动监视器内存标签页看到的尖峰之下。压缩内存生效时,延迟会先飙升再被杀——把这个当作领先指标。
裁剪策略应与内存专文一致:轮转会话记录、限制 JSON 深度、在网关拒绝超大附件而不是让 Node 先解析。
若网关集成了向量检索或本地嵌入,峰值往往出现在批量索引阶段;此时临时禁用无关 skill 或降低批大小,比盲目调高 Node --max-old-space-size 更安全。
何时采样 Node 进程
若 CPU 连续两分钟以上卡在 100% 且日志无进展,请在活动监视器抓取样本并与 plist 版本一并归档。样本能暴露自定义中间件里的紧循环,这类问题未必以传统堆栈形式出现在 stderr。
Plist:KeepAlive、RunAtLoad
仅在零退出真的代表“不健康”时,才在 KeepAlive 下使用 SuccessfulExit。布尔值配错会让 launchd 重启本应健康的关机,徒耗云端 Mac 主机的 CPU 额度。用 launchctl print gui/$UID/your.label 验证并截图输出以便变更管理。
为何 Linux CI 无法复现
CI 容器缺少相同的统一内存压缩、launchd 作业生命周期与钥匙串提示。把 Linux 测试当作静态检查:网关构建仍应在 macOS 上冒烟。租用 Mac mini 每天大约16.9 美元即可补上缺口,而不必寄送笔记本。
国内网络环境下,还要注意镜像拉取与模型缓存路径是否在 CI 与 macOS 上一致;否则你会在 Linux 上“全绿”,上线后却被磁盘路径差异触发退出码 1。
复盘模板
- 从最后健康请求 id 到第一条崩溃日志的时间线。
- 退出码、信号与 launchd 原因字符串。
- 内存高水位与并发工具数量。
- doctor 输出哈希与自上次部署以来的配置 diff。
- 后续动作:代码、plist 或容量。
Stderr 轮转与磁盘满
部分网关在 StandardErrorPath 无法追加时会以码 1 退出。macOS 统一日志会轮转,普通文件不会。监控 /private/var 与自定义日志目录的剩余空间;多代理共享的 Mac mini 至少保留5 GB余量。
优先用 newsyslog 或文档化的 logrotate 包装,而不是无限增长的单文件——在压力下解析12 GB stderr 尾部往往是二次事故。
部署脚本中的信号纪律
蓝绿脚本常发 SIGTERM,等待 15 秒后升级到 SIGKILL。若 Node 捕获 SIGTERM 以排空 HTTP,但工具调用超过宽限期,launchd 仍会记下137——即便运维以为停机很干净。延长宽限期或在换二进制前降低在途工具扇出。
暴露 /readyz 端点在 SIGTERM 前置为 false,让负载均衡立即停止投递请求——这比单独调 Node 标志更能减少强杀。
飞行记录器:最小常驻指标
即便小规模安装也导出 process_start_timestamp_seconds、process_exit_code、rss_bytes_max 到 Prometheus。退出码飙升时,这三条序列能区分内存、部署抖动还是配置漂移,而不必打开笔记本。
常见问题
137 是否总是 OOM?
网关上通常如此;仍需对照内存曲线。
部署后为何立刻 143?
launchd 在重载时终止旧进程。
stderr 在哪?
查看 LaunchAgent plist 的 StandardErrorPath。
何时租 Mac mini?
当你需要忠实的 launchd 与内存行为时。
退出码考古繁琐,但比事故分钟便宜。带 Apple Silicon 的实体 Mac mini 能复现 launchd 退避、内存压缩与文件描述符默认值——这些都与 Linux 预发布环境不同。MacHTML 提供带 SSH/VNC 的机器,让你在发布周末保持在线诊断,周一再关机——弹性容量而不必再开 CapEx 工单。
安静硬件也有助于你在视频会议上向分布式团队朗读日志而不被风扇盖过。
在真实 macOS launchd 上复现 OpenClaw 退出
租用云 Mac mini,在升级网关前验证退出码、plist 重载行为与 Console 证据。