进程生命周期与运行时架构

本文档从操作系统进程视角分析 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.tsrunGatewayCommand()
核心src/cli/gateway-cli/run-loop.tsrunGatewayLoop()
实现src/gateway/server.impl.tsstartGatewayServer()
启动openclaw gateway run

Gateway 是整个系统的核心,启动后进入无限循环保活(run-loop.ts 第 229 行),职责包括:

  • 监听 WebSocket 连接,接收客户端/节点请求
  • 管理会话状态并广播更新
  • 协调 Channel 插件进行消息投递
  • 调度 Agent Turn 处理请求
  • 管理 Memory 索引操作

信号处理

  • SIGTERM / SIGINT → 优雅关闭(5 秒超时)
  • SIGUSR1 → 进程内重启(先排空活跃任务,最长 90 秒)

2.2 维护定时器

项目说明
入口src/gateway/server-maintenance.tsstartGatewayMaintenanceTimers()
启动Gateway 启动时自动创建
生命周期随 Gateway 关闭而清除

通过 setInterval 驱动的周期任务:

定时器职责
Tick keepalive向所有连接客户端发送心跳
Health refresh定期探测 Gateway 健康状态
Dedupe cleanup清理消息去重缓存
Media cleanup清理过期的媒体缓存文件(可选)

2.3 命令队列 / 任务通道

项目说明
入口src/process/command-queue.tssrc/process/lanes.ts
启动Gateway 内部初始化

按通道(lane)串行调度任务执行。默认通道为 main,定时任务使用 cron 通道。队列仅存在于内存中,Gateway 重启后丢失。

2.4 Channel 插件监听

项目说明
入口src/gateway/server-channels.tscreateChannelManager()
健康监控src/gateway/channel-health-monitor.ts
插件实现extensions/*/src/monitor/ 目录
启动Gateway 启动时按已配置账号逐个启动

每个已配置的 Channel 账号(如一个 Telegram bot、一个 Discord 服务器、一个 Slack 工作区)维护一个独立的长连接或轮询循环:

Channel监听方式
TelegramBot API 轮询(getUpdates
DiscordWebhook 监听
SlackEvents API webhook
Signal / Zalo 等各插件自定义

失败策略:单个账号失败时指数退避重启(最多 10 次),不影响其他 Channel。

2.5 Memory 文件监听

项目说明
初始化src/gateway/server-startup-memory.tsstartGatewayMemoryBackend()
核心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.tsstartGmailWatcherWithLogs()
启用条件配置了 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.tsloadInternalHooks()
启动Gateway 启动时注册

事件驱动架构,监听 gateway:startupsession:created 等事件,触发时异步执行(fire-and-forget)。

2.9 macOS 菜单栏 App(独立进程)

项目说明
入口apps/macos/Sources/OpenClaw/
IPCapps/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

跨平台服务托管:

平台服务管理器
macOSlaunchd
Linuxsystemd
WindowsWindows Service Manager

通过环境变量 OPENCLAW_SERVICE_MARKER 告知 Gateway 当前处于托管模式。


三、按需组件(执行完即退出)

3.1 CLI 命令

项目说明
入口src/cli/run-main.tssrc/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.tsagentCommand()
运行时src/agents/pi-embedded.tssrc/agents/pi-embedded-runner/
触发收到消息时 Gateway 内部调用

Agent 不是常驻的。每次收到消息才创建一个 Agent Turn,职责包括:

  • 调用 LLM 模型(OpenAI、Anthropic、Gemini 等)
  • 执行工具(bash、文件访问、浏览器控制、消息发送)
  • 管理 Memory 索引和检索
  • 处理 Hook 回调
  • 定期压缩会话历史

一轮对话结束后,会话状态持久化到磁盘,Agent Turn 资源释放。

3.3 Bash / 系统命令子进程

项目说明
入口src/process/exec.tsrunExec()
管理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.tssrc/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.tsscheduleGatewayUpdateCheck()
触发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 ServerWebSocket 客户端、CLI 命令、WebhookWebSocket 更新、HTTP 调用、stdout 日志WS、HTTP、stdio
Channel 插件平台 API 消息Agent 调用、平台回复HTTP/Webhook、内部 SDK
Agent TurnGateway 队列分发的消息工具调用、LLM 请求、Memory 更新进程内调用、HTTP
Memory Manager文件系统变更、embedding 请求磁盘写入、HTTP 调用 embedding APIFile I/O、HTTP
macOS App用户 UI 交互IPC 命令到 GatewayUnix domain socket
Bash 子进程supervisor 通过 stdin 输入stdout/stderr 输出到 supervisor管道(Pipes)
CLI 命令argv 参数exit code、stdout/stderrstdio

七、关键结论

  1. Gateway 是唯一的主进程:所有常驻组件(定时器、Channel 监听器、文件 Watcher)都是 Gateway 进程内的子系统,不是独立的操作系统进程。
  2. Agent 不是常驻的:每次收到消息才创建 Agent Turn,请求级别的生命周期,完成即释放。
  3. 真正的子进程只有两种:Agent 执行 bash 工具时 spawn() 的 shell 进程,和媒体处理时 spawn() 的 ffmpeg 进程。
  4. macOS App 是唯一的独立常驻进程:通过 Unix domain socket 与 Gateway IPC 通信,两者可独立运行。
  5. Channel 监听器是长连接但非独立进程:跑在 Gateway 进程内,每个账号维护独立的轮询/WebSocket 循环,单个失败不影响其他 Channel。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐