OpenClaw 学习系列之十四:进程生命周期与运行时架构
进程生命周期与运行时架构
本文档从操作系统进程视角分析 OpenClaw 的运行时架构,区分常驻组件与按需组件。
一、架构总览
OpenClaw 运行时以 Gateway 为唯一主进程,所有常驻组件(定时器、Channel 监听器、文件 Watcher)都是该进程内的子系统,而非独立进程。真正通过 spawn() 创建的操作系统子进程只有 Agent 执行 bash 工具和媒体处理(ffmpeg)时才会出现。
┌─────────────────────────────────────────────────────────┐
│ Gateway 主进程 │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌───────────────┐ │
│ │ WebSocket │ │ 维护定时器 │ │ 命令队列 │ │
│ │ Server │ │ (心跳/健康) │ │ (任务通道) │ │
│ └──────────────┘ └──────────────┘ └───────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌───────────────┐ │
│ │ Channel │ │ Memory │ │ Hook │ │
│ │ 插件监听 │ │ 文件监听 │ │ 事件系统 │ │
│ └──────────────┘ └──────────────┘ └───────────────┘ │
│ │
│ ┌──────────────────────────────────────┐ │
│ │ Agent Turn(按需创建,完成即释放) │ │
│ │ ├─ LLM API 调用 │ │
│ │ ├─ spawn() bash 子进程 │ │
│ │ └─ spawn() ffmpeg 子进程 │ │
│ └──────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
┌───────────────────┐
│ macOS 菜单栏 App │ ← 独立进程,通过 Unix domain socket IPC
└───────────────────┘
二、常驻组件(启动后持续运行)
2.1 Gateway 主循环
| 项目 | 说明 |
|---|---|
| 入口 | src/cli/gateway-cli/run.ts → runGatewayCommand() |
| 核心 | src/cli/gateway-cli/run-loop.ts → runGatewayLoop() |
| 实现 | src/gateway/server.impl.ts → startGatewayServer() |
| 启动 | openclaw gateway run |
Gateway 是整个系统的核心,启动后进入无限循环保活(run-loop.ts 第 229 行),职责包括:
- 监听 WebSocket 连接,接收客户端/节点请求
- 管理会话状态并广播更新
- 协调 Channel 插件进行消息投递
- 调度 Agent Turn 处理请求
- 管理 Memory 索引操作
信号处理:
SIGTERM/SIGINT→ 优雅关闭(5 秒超时)SIGUSR1→ 进程内重启(先排空活跃任务,最长 90 秒)
2.2 维护定时器
| 项目 | 说明 |
|---|---|
| 入口 | src/gateway/server-maintenance.ts → startGatewayMaintenanceTimers() |
| 启动 | Gateway 启动时自动创建 |
| 生命周期 | 随 Gateway 关闭而清除 |
通过 setInterval 驱动的周期任务:
| 定时器 | 职责 |
|---|---|
| Tick keepalive | 向所有连接客户端发送心跳 |
| Health refresh | 定期探测 Gateway 健康状态 |
| Dedupe cleanup | 清理消息去重缓存 |
| Media cleanup | 清理过期的媒体缓存文件(可选) |
2.3 命令队列 / 任务通道
| 项目 | 说明 |
|---|---|
| 入口 | src/process/command-queue.ts、src/process/lanes.ts |
| 启动 | Gateway 内部初始化 |
按通道(lane)串行调度任务执行。默认通道为 main,定时任务使用 cron 通道。队列仅存在于内存中,Gateway 重启后丢失。
2.4 Channel 插件监听
| 项目 | 说明 |
|---|---|
| 入口 | src/gateway/server-channels.ts → createChannelManager() |
| 健康监控 | src/gateway/channel-health-monitor.ts |
| 插件实现 | 各 extensions/*/src/monitor/ 目录 |
| 启动 | Gateway 启动时按已配置账号逐个启动 |
每个已配置的 Channel 账号(如一个 Telegram bot、一个 Discord 服务器、一个 Slack 工作区)维护一个独立的长连接或轮询循环:
| Channel | 监听方式 |
|---|---|
| Telegram | Bot API 轮询(getUpdates) |
| Discord | Webhook 监听 |
| Slack | Events API webhook |
| Signal / Zalo 等 | 各插件自定义 |
失败策略:单个账号失败时指数退避重启(最多 10 次),不影响其他 Channel。
2.5 Memory 文件监听
| 项目 | 说明 |
|---|---|
| 初始化 | src/gateway/server-startup-memory.ts → startGatewayMemoryBackend() |
| 核心 | src/memory/manager.ts |
| 启动 | Gateway 启动时初始化 |
组件包括:
- 文件 Watcher(chokidar):监听工作区目录的文件变更
- Session Watcher:追踪会话记录变化
- Batch Embedding Queue:将文本块批量发送到 embedding 提供商
- SQLite 向量数据库:存储向量和元数据(详见 11. SQLite 存储结构)
2.6 Gmail Watcher(可选)
| 项目 | 说明 |
|---|---|
| 入口 | src/hooks/gmail-watcher-lifecycle.ts → startGmailWatcherWithLogs() |
| 启用条件 | 配置了 hooks.gmail.account |
定期轮询 Gmail API,检测到新邮件时触发 Agent Turn 处理。
2.7 Browser Control Server(可选)
| 项目 | 说明 |
|---|---|
| 入口 | src/gateway/server-browser.ts |
| 启用条件 | Canvas/浏览器自动化功能启用时 |
HTTP 服务,管理浏览器会话供 Agent 使用。
2.8 内部 Hook 系统
| 项目 | 说明 |
|---|---|
| 入口 | src/hooks/loader.ts → loadInternalHooks() |
| 启动 | Gateway 启动时注册 |
事件驱动架构,监听 gateway:startup、session:created 等事件,触发时异步执行(fire-and-forget)。
2.9 macOS 菜单栏 App(独立进程)
| 项目 | 说明 |
|---|---|
| 入口 | apps/macos/Sources/OpenClaw/ |
| IPC | apps/macos/Sources/OpenClawIPC/(Unix domain socket) |
| 启动 | 用户手动启动或 launchd 托管 |
唯一独立于 Gateway 的常驻 GUI 进程。SwiftUI 原生应用,提供:
- 菜单栏状态显示
- Gateway 启停控制
- Channel 连接状态查看
- 会话历史浏览
通过 Unix domain socket 与 Gateway 进行 IPC 通信。Gateway 可以脱离 App 独立运行。
2.10 Daemon 服务管理
| 项目 | 说明 |
|---|---|
| 入口 | src/cli/daemon-cli/、src/daemon/service.ts |
| 启动 | openclaw daemon install |
跨平台服务托管:
| 平台 | 服务管理器 |
|---|---|
| macOS | launchd |
| Linux | systemd |
| Windows | Windows Service Manager |
通过环境变量 OPENCLAW_SERVICE_MARKER 告知 Gateway 当前处于托管模式。
三、按需组件(执行完即退出)
3.1 CLI 命令
| 项目 | 说明 |
|---|---|
| 入口 | src/cli/run-main.ts → src/commands/* |
| 触发 | openclaw <command> |
每次调用创建一个进程,执行完退出。典型命令:
| 命令 | 用途 |
|---|---|
openclaw agent <key> <msg> | 执行一轮对话 |
openclaw config get/set | 读写配置 |
openclaw message send | 通过 Channel 发送消息 |
openclaw health | 探测 Gateway 状态 |
openclaw setup | 引导式配置向导 |
3.2 Agent Turn
| 项目 | 说明 |
|---|---|
| 入口 | src/agents/agent-command.ts → agentCommand() |
| 运行时 | src/agents/pi-embedded.ts、src/agents/pi-embedded-runner/ |
| 触发 | 收到消息时 Gateway 内部调用 |
Agent 不是常驻的。每次收到消息才创建一个 Agent Turn,职责包括:
- 调用 LLM 模型(OpenAI、Anthropic、Gemini 等)
- 执行工具(bash、文件访问、浏览器控制、消息发送)
- 管理 Memory 索引和检索
- 处理 Hook 回调
- 定期压缩会话历史
一轮对话结束后,会话状态持久化到磁盘,Agent Turn 资源释放。
3.3 Bash / 系统命令子进程
| 项目 | 说明 |
|---|---|
| 入口 | src/process/exec.ts → runExec() |
| 管理 | src/process/supervisor/ |
| 工具 | src/agents/bash-tools.ts |
| 触发 | Agent 调用 bash 工具 |
通过 spawn() 创建真正的操作系统子进程,具备超时控制和 PTY 管理。完成或超时后销毁。
3.4 子 Agent
| 项目 | 说明 |
|---|---|
| 入口 | src/agents/tools/subagents-tool.ts |
| 触发 | 父 Agent 调用 subagents 工具 |
在 Gateway 进程内嵌套执行,结果返回父 Agent 后释放。
3.5 媒体处理
| 项目 | 说明 |
|---|---|
| 入口 | src/media/ffmpeg-exec.ts、src/media/host.ts |
| 理解 | src/media-understanding/runner.ts |
| 触发 | Agent 处理图片/音视频时 |
通过 spawn() 创建 ffmpeg 子进程进行格式转换、编码等操作,处理完退出。
3.6 Embedding 批处理
| 项目 | 说明 |
|---|---|
| 入口 | src/memory/batch-runner.ts |
| 触发 | Memory Manager 检测到文件变更 |
异步 HTTP 调用 embedding API,批次完成后结束。大批量可能持续数分钟到数小时,但不会跨 Gateway 重启持久化。
3.7 LLM API 调用
| 项目 | 说明 |
|---|---|
| 入口 | src/agents/model-*、src/agents/anthropic-*.ts |
| 触发 | Agent Turn 中的思考和回复生成 |
直接 HTTP 请求,支持流式和批量,不创建子进程。
3.8 更新检查
| 项目 | 说明 |
|---|---|
| 入口 | src/infra/update-startup.ts → scheduleGatewayUpdateCheck() |
| 触发 | Gateway 启动时一次性调度 |
查询 npm registry 检查版本更新,不阻塞 Gateway 启动。
四、启动时序
openclaw gateway run
│
▼
① Gateway 主循环 (run-loop.ts)
│ 获取端口锁
▼
② 服务启动 (server.impl.ts)
│ 加载配置 → 加载插件 → 初始化 secrets
│
├──→ ③ Browser Control Server(可选)
├──→ ④ Gmail Watcher(可选)
├──→ ⑤ Internal Hooks 注册
├──→ ⑥ Channel 插件启动(每个账号一个监听器)
│
▼
⑦ 维护定时器启动
│ 心跳 / 健康检查 / 去重清理
▼
⑧ Memory 后端初始化
│ 打开 SQLite → 启动文件监听 → 启动 embedding 批处理
▼
⑨ Gateway Ready —— 开始接受 WebSocket 连接
│
│ 收到消息
▼
Agent Turn(按需创建,完成即释放)
├─ LLM API 调用(HTTP,非子进程)
├─ bash 工具 → spawn() 子进程 → 完成/超时后销毁
└─ 媒体处理 → spawn() ffmpeg → 完成后销毁
五、关闭时序(SIGTERM / SIGINT)
收到信号
│
▼
① 设置 shuttingDown 标志
│
▼
② 拒绝新任务入队
│
▼
③ 等待活跃任务完成
│ 普通关闭:5 秒超时
│ 重启(SIGUSR1):最长 90 秒排空
▼
④ 关闭 WebSocket 连接
│
▼
⑤ 停止所有定时器
│
▼
⑥ 关闭 Memory Manager
│
▼
⑦ 释放端口锁
│
▼
⑧ 进程退出
exit(0) 正常关闭
exit(1) 重启超时
六、进程间通信方式
| 进程/组件 | 入站 | 出站 | 协议 |
|---|---|---|---|
| Gateway Server | WebSocket 客户端、CLI 命令、Webhook | WebSocket 更新、HTTP 调用、stdout 日志 | WS、HTTP、stdio |
| Channel 插件 | 平台 API 消息 | Agent 调用、平台回复 | HTTP/Webhook、内部 SDK |
| Agent Turn | Gateway 队列分发的消息 | 工具调用、LLM 请求、Memory 更新 | 进程内调用、HTTP |
| Memory Manager | 文件系统变更、embedding 请求 | 磁盘写入、HTTP 调用 embedding API | File I/O、HTTP |
| macOS App | 用户 UI 交互 | IPC 命令到 Gateway | Unix domain socket |
| Bash 子进程 | supervisor 通过 stdin 输入 | stdout/stderr 输出到 supervisor | 管道(Pipes) |
| CLI 命令 | argv 参数 | exit code、stdout/stderr | stdio |
七、关键结论
- Gateway 是唯一的主进程:所有常驻组件(定时器、Channel 监听器、文件 Watcher)都是 Gateway 进程内的子系统,不是独立的操作系统进程。
- Agent 不是常驻的:每次收到消息才创建 Agent Turn,请求级别的生命周期,完成即释放。
- 真正的子进程只有两种:Agent 执行 bash 工具时
spawn()的 shell 进程,和媒体处理时spawn()的 ffmpeg 进程。 - macOS App 是唯一的独立常驻进程:通过 Unix domain socket 与 Gateway IPC 通信,两者可独立运行。
- Channel 监听器是长连接但非独立进程:跑在 Gateway 进程内,每个账号维护独立的轮询/WebSocket 循环,单个失败不影响其他 Channel。
更多推荐



所有评论(0)