openclaw源码解读(7)——server.impl.ts 真正的启动引擎 第四阶段(2):全景 从处理器组装到上线返回

📅 2026/8/23 9:30:29
openclaw源码解读(7)——server.impl.ts 真正的启动引擎 第四阶段(2):全景 从处理器组装到上线返回
第四阶段2全景从处理器组装到上线返回块1L1708-1765 — 插件热替换基础设施。replaceAttachedPluginRuntime(loaded) 运行时更换插件注册表的工具函数做五件事替换全局 pluginRegistry 引用重建 attachedGatewayMethodRegistry合并新旧方法描述符刷新 runtimeState.gatewayMethods 列表调用三个 pin* 函数重新绑定插件路由/会话扩展/通道注册刷新节点的插件工具列表refreshAttachedGatewayDiscovery(nextPluginRegistry) 刷新gataway发现器让别的服务也能发现gateway的这些方法。插件变了→Bonjour 广播也要变。先停旧的、再启新的。块2L1769-1880 —重新加载gateway插件插件热重载引擎reloadAttachedGatewayPlugins({ nextConfig, changedPaths, ... }) 这是 config reload 时用的核心函数流程对比新旧 channel 集合│├─ 找出需要停掉的 channel删除的 / 配置变更的├─ 调用 beforeReplace() 停掉它们├─ commitRuntime() 提交新 runtime├─ prepareGatewayPluginLoad() 加载新插件├─ replaceAttachedPluginRuntime() 替换注册表├─ 停旧 pluginServices → 启新 pluginServices├─ refreshAttachedGatewayDiscovery() 刷新发现└─ 对比前后 channel diff → 返回 restartChannels关键设计先停后启不是原地修改——旧 pluginServices 在替换完成后才 stop确保过渡期不影响正在处理的请求。块3L1886-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, terminalLaunchPolicyChat RunchatAbortControllers, chatRunState(buffers/plan/delta), addChatRun/removeChatRun会话事件subscribeSessionEvents, sessionEventSubscribers, sessionMessageSubscribersWizardwizardSessions, findRunningWizard, purgeWizardSessionWorkerworkerEnvironmentService, workerSessionPlacementService块4L1981-1991 — 创建 GatewayInstanceRuntimeconst gatewayInstanceRuntimeLocal createGatewayInstanceRuntime({getContext: () gatewayRequestContext,getMethodRegistry: () attachedGatewayMethodRegistry,isDispatchAvailable: () gatewayInstanceDispatchReady !closePreludeStarted,});// 回填到 request contextgatewayRequestContext.approvalEvents gatewayInstanceRuntimeLocal.approvalEvents;gatewayRequestContext.recoveryRuntime gatewayInstanceRuntimeLocal.recovery;gatewayInstanceRuntime 是请求分发的入口控制着哪些方法可以调用method registry当前是否可以分发dispatch available审批事件推送恢复运行时restart recoverygatewayInstanceDispatchReady此时还是false要等 HTTP 服务器真正 listen 后才翻 true。这是重要的安全阀——bind 之前任何请求都不能进入。块5L1993-2023 — 回退上下文 延迟插件setFallbackGatewayContextResolver(() gatewayRequestContext);设置一个 fallback某些极端情况下比如还没创建完就需要 gateway context能用。if (!minimalTestGateway runtimePluginsLoaded deferredConfiguredChannelPluginIds.length 0) {reloadDeferredGatewayPlugins(...) // 加载延迟配置的 channel 插件}有些插件不需要在早期启动时就加载而是在此时延迟加载。块6L2025-2075 — WebSocket 处理器挂载 开始监听await startupTrace.measure(gateway.ws-attach, () attachGatewayWsHandlers({ wss, clients, ... }));把 WebSocket 的 upgrade/connection/message 等事件处理器挂载到 wssWebSocket Server上。此时客户端还不能连接。构建wssWebSocket Server handler 对象 L2033-2062await startupTrace.measure(http.listen, () startListening());gatewayInstanceDispatchReady true;startupTrace.mark(http.bound);这两行是整个启动流程的分水岭。startListening() → HTTP 服务器在指定端口上开始 listen()接受 TCP 连接gatewayInstanceDispatchReady true → 分发阀门打开请求可以进来了http.bound → 启动追踪标记完成块7L2073-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-2216onSidecarsReady: () { L2207-2210startupSidecarsReady true;activateScheduledServicesWhenReady(); // ← 触发门控},onChannelsStarted: () { L2165-2167releaseStartupAccountStarts(); // ← 释放之前阻塞的 account 启动},});回调设计很优雅所有异步的 sidecar 完成后各自调用回调最终 converge 到 onSidecarsReady→激活定时服务。L2220-2234:开启gateway进程的内存使用情况的跟踪日志标志gateway ready完成gateway重启内存情况跟踪日志如果非测试环境在runtimeState中加入一条 验证openclaw数据库完整性postAttachRuntimeReturned 为true激活准备好的计划服务activateScheduledServicesWhenReady块8L2237-2390 — Config Reloader Post-Ready 维护startManagedGatewayConfigReloader()├─ 监听配置文件变更 L2246-2261├─ 比对 hooks/cron/heartbeat/channel 状态 L2264-2270├─ 热更新 runtimeState不重启进程L2271-2282├─ 需要时调用 reloadAttachedGatewayPlugins() L2287└─ 支持 cron 重启、终端配置变更等 L2293-2307promoteConfigSnapshotToLastKnownGood() L2319-2321└─ 把启动时加载的配置标记为已知良好备份scheduleGatewayPostReadyMaintenance()├─ 延迟 POST_READY_MAINTENANCE_DELAY_MS L2325├─ 启动周期 tick L2348├─ 启动健康检查定时器 L2349├─ 启动 dedupe 清理 L2350├─ 启动 media 清理 L2351├─ 启动 worktree 清理 L2352└─ 启动 cron如果还没启动L2355scheduleGatewayIdleTask() L2371-2383└─ 清理旧版 plugin 安装残留块9L2396-EOF — 返回 Close 函数} catch (err) {await closeOnStartupFailure(); // 任何阶段失败 → 执行完整关闭流程throw err;}const close createCloseHandler(); // 创建关闭处理器return {close: async (optsLocal) {await beginClosePrelude(); // ① 标记 drainingterminalSessions.disposeAll(); // ② 关所有终端await stopRegisteredGatewayLifetimeSidecars(); // ③ 停生命周期 sidecarawait stopRegisteredPostReadySidecars(); // ④ 停 post-ready sidecarawait 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 的骨架。