中文 | English
基于 Electron utilityProcess + MessageChannelMain 的生产级多进程 RPC 框架,
配套无侵入 Debug Panel(Ctrl+Shift+D 呼出)。
npm install
npm run dev # 开发模式(HMR,Debug Panel 自动挂载)
npm run build # 产出 out/
npm run start # 运行构建产物
npm run typecheck # 类型检查Renderer Main Utility 进程池
─────── ──── ─────────────
client.download.start() ──► Gateway(ipcMain.handle) ──► RuntimeManager ──► [io-network] DownloadModule
│ (Proxy 自动注入 rt) │ Debug 埋点 │ 懒加载/熔断/心跳 │ MessageChannelMain 点对点
│ │ └─► [native-heavy] ImageModule
▼ ▼
onProgress(cb) ◄──────── EventRouter(精确订阅投递) ◄──────── emitEvent()(事件经 Port 上行)
DebugCollector ── xpc:debug:push ──► DebugPanel(仅推给订阅窗口)
- 强类型契约:
src/shared/protocol.ts是单一数据源,前端调用具备完整 IDE 提示。 - 信封协议:所有跨进程消息遵循
{ type, id, module, method/…, payload },主进程只做路由中转,不执行业务。 - 进程隔离:
image.compress崩溃不影响download;Utility 之间禁止直连。
| # | 问题 | 修复 | 位置 |
|---|---|---|---|
| 1 | moduleRuntimeMap 手抄不同步 |
RUNTIME_OF_MODULE 与契约同文件,as const satisfies ModuleRuntimeMap 编译期强制同步 |
shared/protocol.ts |
| 2 | Port 假死 + 过期消息积压 | 请求携带 ts,Utility 引擎丢弃超 TTL(15s) 的积压请求;主进程 5s 心跳 ping、15s 无 pong 标记 unresponsive,恢复自动转绿 |
utility/engine.ts、main/runtime-manager.ts |
| 3 | 事件广播泄漏/野指针 | EventRouter:channel → webContentsId → 引用计数,无人订阅零开销;Preload 端 0→1 注册、1→0 注销;窗口销毁自动清理 |
main/gateway.ts、preload/index.ts |
| 4 | 崩溃无限复活死循环 | 熔断器:60s 窗口内崩溃 ≥5 次拒绝重生,RPC 直接 reject 提示用户;主动 shutdown 不计崩溃 | main/runtime-manager.ts |
| 5 | 大数据序列化瓶颈 | 演示 allocNoise 返回 32MB ArrayBuffer 二进制直传(避免 base64 33% 膨胀);reply 预留 transfer 透传位 |
utility/modules/image.module.ts |
| 6 | 调试黑盒 | Debug Panel(订阅制推送)+ Utility console 重定向到主进程([xpc:xxx] 前缀)+ rpc_res 错误携带真实堆栈 + 三端 sourcemap |
debug-collector.ts、engine.ts |
- Start Download:RPC 路由到
io-network,进度事件流驱动进度条(Debug Panel 可见 RPC 日志与download.progress订阅计数)。 - Alloc 32MB Binary:二进制直传性能演示。
- 💥 Crash native-heavy:进程 exit(86) → pending 全部 reject → Panel 显示 🔴 crashed → 再次调用自动重生(连续 5 次触发熔断 ⛔)。
- Block 2s / 17s:事件循环阻塞 → Panel 显示 🟠 unresponsive(心跳失联)→ 恢复转绿;17s 超过 TTL,主进程超时拒绝,阻塞期间排队的请求恢复后被 Utility 丢弃(主进程控制台可见"丢弃过期 RPC"日志)。
- Electron
MessagePortMain.postMessage的 transfer 列表仅支持转移MessagePort本身,不支持 ArrayBuffer 零拷贝转移(与浏览器 MessagePort 不同)。因此大数据优化采用原生二进制结构化克隆(相比 base64 字符串已省去 33% 膨胀与字符串编解码成本);需要真零拷贝时可评估SharedArrayBuffer共享内存。 - Debug Panel 仅在开发环境挂载(
import.meta.env.DEV)。
src/
├── shared/
│ ├── protocol.ts # 核心契约 + RUNTIME_OF_MODULE(单一数据源)
│ └── debug.ts # Debug Panel 数据契约
├── main/
│ ├── index.ts # 主进程入口
│ ├── runtime-manager.ts # 进程池:懒加载/超时/崩溃恢复/熔断/心跳
│ ├── gateway.ts # IPC 网关 + EventRouter 精确订阅
│ └── debug-collector.ts # Debug 采集与订阅制推送
├── utility/
│ ├── engine.ts # Utility 引擎:RPC 分发/TTL 丢弃/日志转发
│ ├── bootstrap-io.ts # io-network 启动入口
│ ├── bootstrap-native.ts # native-heavy 启动入口
│ └── modules/ # 业务模块(download / image)
├── preload/index.ts # 安全桥接(xpc + xpcDebug)
└── renderer/
├── client.ts # 强类型 Proxy 客户端
├── App.tsx # 演示界面
└── debug-panel/ # Debug Panel 组件
npm run test:smoke # 无 GUI 冒烟自检:spawn/双 Runtime 路由/崩溃拒绝/自动重生,退出码报告
npm run test:e2e # Python 编排器黑盒驱动真实构建产物(CDP + window.xpc 桥)E2E 编排器(tests/)跑 5 个场景共 28 项断言:RPC 路由、事件流、崩溃恢复、二进制直传、
心跳/TTL/过期丢弃。确定性事实用普通断言;用例失败时才调用 TypeSafe Jev(System One)
做语义分诊——一次 system_one 往返同时问错误分类(Choice)、严重度(Score)、是否阻塞
合入(Noul),置信度 < 0.7 标记"需人工复核"而不是硬判。详见 tests/README.md。