openclaw源码解读(7)——server.impl.ts 真正的启动引擎 第四阶段(2):全景 从处理器组装到上线返回
第四阶段(2)全景:从处理器组装到上线返回
块1:L1708-1765 — 插件热替换基础设施。replaceAttachedPluginRuntime(loaded) 运行时更换插件注册表的工具函数,做五件事:
- 替换全局 pluginRegistry 引用
- 重建 attachedGatewayMethodRegistry(合并新旧方法描述符)
- 刷新 runtimeState.gatewayMethods 列表
- 调用三个 pin* 函数重新绑定插件路由/会话扩展/通道注册
- 刷新节点的插件工具列表
refreshAttachedGatewayDiscovery(nextPluginRegistry) 刷新gataway发现器,让别的服务也能发现gateway的这些方法。插件变了→Bonjour 广播也要变。先停旧的、再启新的。
块2:L1769-1880 — 重新加载gateway插件,插件热重载引擎
reloadAttachedGatewayPlugins({ nextConfig, changedPaths, ... }) 这是 config reload 时用的核心函数,流程:
对比新旧 channel 集合
│
├─ 找出需要停掉的 channel(删除的 / 配置变更的)
├─ 调用 beforeReplace() 停掉它们
├─ commitRuntime() 提交新 runtime
├─ prepareGatewayPluginLoad() 加载新插件
├─ replaceAttachedPluginRuntime() 替换注册表
├─ 停旧 pluginServices → 启新 pluginServices
├─ refreshAttachedGatewayDiscovery() 刷新发现
└─ 对比前后 channel diff → 返回 restartChannels
关键设计:先停后启,不是原地修改——旧 pluginServices 在替换完成后才 stop,确保过渡期不影响正在处理的请求。
块3:L1886-1980 — 创建 GatewayRequestContext
设置gateway实例的运行时环境、gateway请求上下文(approvalEvents,recoveryRuntime)
const gatewayRequestContext = await startupTrace.measure(
"gateway.request-context",
() => createGatewayRequestContext({...})
);
这是整个 gateway 的**"上帝对象"**,几乎所有 handler 都通过它访问公共能力。里面包含了:
|
类别 |
内容 |
|
运行时配置 |
getRuntimeConfig, runtimeState, deps |
|
审批系统 |
execApprovalManager, pluginApprovalManager, systemAgentApprovalManager |
|
健康检查 |
getHealthCache, refreshHealthSnapshot, getEventLoopHealth |
|
广播/节点 |
broadcast, broadcastToConnIds, nodeSendToSession, nodeRegistry |
|
终端 |
terminalSessions, terminalLaunchPolicy |
|
Chat Run |
chatAbortControllers, chatRunState(buffers/plan/delta), addChatRun/removeChatRun |
|
会话事件 |
subscribeSessionEvents, sessionEventSubscribers, sessionMessageSubscribers |
|
Wizard |
wizardSessions, findRunningWizard, purgeWizardSession |
|
Worker |
workerEnvironmentService, workerSessionPlacementService |
块4:L1981-1991 — 创建 GatewayInstanceRuntime
const gatewayInstanceRuntimeLocal = createGatewayInstanceRuntime({
getContext: () => gatewayRequestContext,
getMethodRegistry: () => attachedGatewayMethodRegistry,
isDispatchAvailable: () => gatewayInstanceDispatchReady && !closePreludeStarted,
});
// 回填到 request context
gatewayRequestContext.approvalEvents = gatewayInstanceRuntimeLocal.approvalEvents;
gatewayRequestContext.recoveryRuntime = gatewayInstanceRuntimeLocal.recovery;
gatewayInstanceRuntime 是请求分发的入口,控制着:
- 哪些方法可以调用(method registry)
- 当前是否可以分发(dispatch available)
- 审批事件推送
- 恢复运行时(restart recovery)
gatewayInstanceDispatchReady 此时还是 false,要等 HTTP 服务器真正 listen 后才翻 true。这是重要的安全阀——bind 之前任何请求都不能进入。
块5:L1993-2023 — 回退上下文 + 延迟插件
setFallbackGatewayContextResolver(() => gatewayRequestContext);
设置一个 fallback,某些极端情况下(比如还没创建完就需要 gateway context)能用。
if (!minimalTestGateway && runtimePluginsLoaded && deferredConfiguredChannelPluginIds.length > 0) {
reloadDeferredGatewayPlugins(...) // 加载延迟配置的 channel 插件
}
有些插件不需要在早期启动时就加载,而是在此时延迟加载。
块6:L2025-2075 — WebSocket 处理器挂载 + 开始监听
await startupTrace.measure("gateway.ws-attach", () =>
attachGatewayWsHandlers({ wss, clients, ... })
);
把 WebSocket 的 upgrade/connection/message 等事件处理器挂载到 wss(WebSocket Server)上。此时客户端还不能连接。
构建wss(WebSocket Server) handler 对象 L2033-2062
await startupTrace.measure("http.listen", () => startListening());
gatewayInstanceDispatchReady = true;
startupTrace.mark("http.bound");
这两行是整个启动流程的分水岭。
- startListening() → HTTP 服务器在指定端口上开始 listen(),接受 TCP 连接
- gatewayInstanceDispatchReady = true → 分发阀门打开,请求可以进来了
- "http.bound" → 启动追踪标记完成
块7:L2073-2219 — 延迟服务激活 + Post-Attach 运行时
const activateScheduledServicesWhenReady = () => {
// 四个条件全部满足才激活:
// ① 不在关闭中 ② postAttachRuntime 已返回
// ③ 所有 sidecar 就绪 ④ 还没激活过
...
};
这是一个多条件门控:定时服务(cron、heartbeat 等)只在所有依赖都就绪后才启动。
L2082-2102:
加载计划服务模块:
再次检查closePreludeStarted的状态
激活gateway计划服务
设置运行时状态(runtimeState)的心跳、停止刷新调用的模型的花费
startGatewayPostAttachRuntime({ L2109-2219
// Tailscale 设置 L2122-2127
// 启动通道 (startChannels) L2165-2167
// 加载启动插件 L2155-2162
// Worker 环境运行时 L2191-2206
// Provider 认证预热 L2214-2216
onSidecarsReady: () => { L2207-2210
startupSidecarsReady = true;
activateScheduledServicesWhenReady(); // ← 触发门控!
},
onChannelsStarted: () => { L2165-2167
releaseStartupAccountStarts(); // ← 释放之前阻塞的 account 启动
},
});
回调设计很优雅:所有异步的 sidecar 完成后,各自调用回调,最终 converge 到 onSidecarsReady→激活定时服务。
L2220-2234:
开启gateway进程的内存使用情况的跟踪日志
标志:gateway ready
完成gateway重启内存情况跟踪日志
如果非测试环境,在runtimeState中加入一条: 验证openclaw数据库完整性
postAttachRuntimeReturned 为true
激活准备好的计划服务(activateScheduledServicesWhenReady)
块8:L2237-2390 — Config Reloader + Post-Ready 维护
startManagedGatewayConfigReloader()
├─ 监听配置文件变更 L2246-2261
├─ 比对 hooks/cron/heartbeat/channel 状态 L2264-2270
├─ 热更新 runtimeState(不重启进程)L2271-2282
├─ 需要时调用 reloadAttachedGatewayPlugins() L2287
└─ 支持 cron 重启、终端配置变更等 L2293-2307
promoteConfigSnapshotToLastKnownGood() L2319-2321
└─ 把启动时加载的配置标记为"已知良好"备份
scheduleGatewayPostReadyMaintenance()
├─ 延迟 POST_READY_MAINTENANCE_DELAY_MS L2325
├─ 启动周期 tick L2348
├─ 启动健康检查定时器 L2349
├─ 启动 dedupe 清理 L2350
├─ 启动 media 清理 L2351
├─ 启动 worktree 清理 L2352
└─ 启动 cron(如果还没启动)L2355
scheduleGatewayIdleTask() L2371-2383
└─ 清理旧版 plugin 安装残留
块9:L2396-EOF — 返回 + Close 函数
} catch (err) {
await closeOnStartupFailure(); // 任何阶段失败 → 执行完整关闭流程
throw err;
}
const close = createCloseHandler(); // 创建关闭处理器
return {
close: async (optsLocal) => {
await beginClosePrelude(); // ① 标记 draining
terminalSessions.disposeAll(); // ② 关所有终端
await stopRegisteredGatewayLifetimeSidecars(); // ③ 停生命周期 sidecar
await stopRegisteredPostReadySidecars(); // ④ 停 post-ready sidecar
await runGlobalGatewayStopSafely(); // ⑤ 执行 gateway_stop 钩子
await runClosePrelude(); // ⑥ 完整 prelude 清理
await close(optsLocal); // ⑦ 最终关闭(HTTP/WS/通道/cron...)
clearFallbackGatewayContextForServer(); // ⑧ 清回退上下文
},
};
createGatewayServer 最终只返回一个东西:{ close }。 服务器本身是无头的——启动后由内部定时器、WebSocket 连接、事件循环驱动,不需要外部调用任何方法。
完整启动时序总结
createGatewayServer()
│
├─ Phase 1: 配置解析 (L1-L500+)
├─ Phase 2: 基础设施 (L500-L1117)
├─ Phase 3: 网络栈创建 (L1118-L1232)
│ ├─ TLS 加载
│ ├─ ChannelManager 创建
│ ├─ ReadinessChecker 创建
│ └─ createGatewayRuntimeState() → HTTP/WS 服务器创建(未 listen)
│
├─ Phase 4: 运行时组装 (L1233-结束) ◀── 我们这次看的全部
│ ├─ 4.1 终端/Lane/Cron/Close工具函数
│ ├─ 4.2 审批系统 + Gateway 方法注册表
│ ├─ 4.3 插件热替换基础设施
│ ├─ 4.4 GatewayRequestContext(上帝对象)
│ ├─ 4.5 GatewayInstanceRuntime(分发入口)
│ ├─ 4.6 WS 处理器挂载 + startListening() ��
│ ├─ 4.7 延迟服务门控 + Post-Attach Runtime
│ ├─ 4.8 Config Reloader + Post-Ready 维护
│ └─ 4.9 return { close }
│
└─ 运行时:事件循环驱动,等待 WS 连接/HTTP 请求/cron 触发...
到这里 server.impl.ts 就全部读完了。这个文件是 gateway 的心脏,掌握了它的结构就等于掌握了整个 OpenClaw Gateway 的骨架。
更多推荐


所有评论(0)