Files
dsh_shenxian/dsh-server-docs/04-调整方案/75-插件评估新增托管友好性与资源成本两个维度.md
T
admin 5ad755116e chore(docs): 文档库并入代码仓(R4 选 a)+ 索引/台账跟进
1) dsh-server-docs/ 从工作区(原 E:\...\aliyun-dsh-server\dsh-server-docs)**整体并入本仓**,
   保留目录名 ⇒ 仓库内 dsh-server-docs/... 的相对引用天然继续有效;旧目录(含其 .git)已归档到
   工作区 _中间产物_待清理/,未随本提交带入。
2) .gitattributes:新增 `dsh-server-docs/** -text` —— 原文档库是 `* -text` + autocrlf=false,
   必须保持纯 LF,否则会被本仓的 CRLF 规则翻掉。
3) 活引用里的绝对路径已全部改到新位置(docs 的 INDEX / README / scripts / skills + 用户级 skills
   + ~/.workbuddy/settings.json 的 hooks);历史档案(04-调整方案/、archive/)按「只增不改」未动。
   ⚠️ hooks 路径改动需「完全重启会话」才生效(配置是会话启动快照)。
4) 交接单/T08:新增 §16「生产整体切换执行记录」(形态 / 落地动作 / **4 个只有真上线才暴露的真 bug** /
   验收证据 / 回滚命令 / 残留项);台账 T08 行 → 已完成并归档;03-路线图 §二 登记 T08 收尾项。
5) 统一称谓:**「本机」只指跑 WorkBuddy 的开发机**,47 / 106 一律写「远程服务器」。
2026-09-15 18:47:13 +08:00

6.4 KiB
Raw Blame History

75 · 插件评估新增「托管友好性」与「资源成本」两个维度(2026-09-12)

  • 日期:2026-09-12
  • 状态:📋 标准已立(本档只立标准,未改预检脚本)
  • 触发:dsh-univer-office 静态预检判 ok 却在平台上完全不可用,且加载成本 +65.1 MiB → 用户提出「把这个作为插件评估和改造的一个点」
  • 范围:评估维度(候选池导入预检)+ 改造规范(自研 / 改造插件)
  • 关系:接续档案 71(插件兼容性预检:依赖范围 + 导出符号),本档是新增维度,不改变其机制与分级语义

一、为什么需要(案例暴露的两个盲区)

dsh-univer-office 在档案 71 的静态兼容性预检里判 ok(依赖与导出符号全满足)——但它在平台上完全不可用:

预检现状 案例暴露的盲区
查 semver 依赖范围 ✅ 通过(依赖没问题)
查运行时导出符号 ✅ 通过(符号都在)
❌ 不查「它假设的部署形态」 把 http://127.0.0.1:${port} 交给浏览器 → 托管平台必然失效,且平台侧无法补救
❌ 不查资源成本 加载 rss +65.1 MiB(实测)= 实例配额的 1/6

⇒ 兼容 ≠ 可用。 需要补两个维度。


二、新维度 A:托管友好性(Hostability)

判据(一句话)

插件的一切对外交互,是否都能走「平台已有的那一条入口」? 即:浏览器侧只用相对路径;实例侧不依赖本机 loopback 上的网络服务。

检查项

ID 检查 检测方法(复用档案 71 的 walkJs 框架) 等级
H1 bundle 里出现硬编码 loopback 服务地址 文本扫描 127.0.0.1:<port> / localhost:<port> 🟡 出现即警告
H2 client bundle 里出现绝对 URL(http:// 字面量) 只扫 client 侧产物;命中即「会交给浏览器」 🔴 阻断
H3 自建网络监听且非 unix socket 扫描 listen( / createServer 参数形态 🟡 需人工确认是否 loopback-only
H4 交付浏览器的 URL 由 Host 生成,还是客户端自行拼接 人工研判(架构文档 + client 代码) 🔴 若客户端自拼绝对地址

为什么 H2 是阻断级:绝对地址一旦交给浏览器,在托管平台上必失效——跨机器(127.0.0.1 指向用户本机)+ HTTPS 混合内容会被浏览器硬拦,且平台侧无补救手段(不能靠配置、不能靠反代)。这正是本案例的死因。

反面样板(本案例实测)

viewerUrl = `${gateway}/?file=...`        // ← 交给浏览器的绝对 URL
gateway   = `http://127.0.0.1:${port}`    // ← 硬编码 loopback,且被浏览器 iframe 使用

两条独立阻碍,缺一都打不开:

  1. Host → Gateway:实例内进程 uid 100002 → 127.0.0.0/8 被 nft reject with tcp reset
  2. Browser → Gateway:绝对 loopback URL,浏览器在用户电脑上 → 即使解封第 1 条也打不开

正面样板(同一插件内)

  • Client(浏览器模块):只走 /univer-api/* 同域相对路径 → ✅ 平台可反代
  • 平台自研 ×3:加载成本 0.0 MiB、无自建监听 → ✅

三、新维度 B:资源成本(Resource Cost)

项 判据 方法
加载内存 插件 import 后的 rss 增量 隔离 cgroup 内逐个 import 实测(node --expose-gc,MemoryMax 兜底)
标注阈值 > 30 MiB → 标注;> 60 MiB → 强提示 同上

实测基线(guest 实例,2026-09-12)

插件 rss 增量
dsh-univer-office +65.1 MiB
libsql(间接依赖) +7.8 MiB
平台自研 ×3(portal-entry / workspace-scoped-picker / business-plugins) 0.0 MiB
puppeteer-core(仅 import 主入口、未启动浏览器) 0.0 MiB

⇒ 成本由「装了什么」决定,不是「装了几个」 —— 一个重型插件 ≈ 无穷多个轻量插件。 ⇒ 平台自研插件的 0.0 MiB 是正面基线,应作为自研插件的验收参考。


四、改造规范(自研 / 改造插件必须满足)

# 规范 理由
R-a 对外入口唯一:浏览器可达面全部挂在 Host 的 webServer(同域相对路径) 复用平台反代,零新增暴露面
R-b 内部通信走 IPC:unix domain socket 或 stdio,不用 TCP loopback 不经 IP 层 ⇒ nft 管不到;天然无端口冲突
R-c 不新增监听端口 多租户同主机下,端口 = 跨租户风险 + 端口漂移
R-d 重型依赖懒加载:原生绑定、引擎等改 await import() 实测有效:puppeteer-core 仅 import 主入口 = 0.0 MiB
R-e 交付浏览器的地址一律由 Host 生成且为相对路径 绝对地址在托管平台必失效

五、落地方式(未实施,待排期)

步 动作 落点
1 兼容性预检加 H1/H2 静态扫描(复用 walkJs) dsh-server-docs/scripts/plugin-compat-check.mjs
2 H2 命中 → 判 blocked,理由「向浏览器交付绝对地址,托管平台不可用」 同上(沿用档案 71 的分级语义)
3 资源成本:预检阶段先做静态体积提示(解包后 artifacts/ 体积),精确值留隔离实测 同上
4 自研插件按 §四 规范执行(T03 的 MCN suite 起适用) 交接单/T03

⚠️ 本档只立标准。改预检脚本属生产代码变更,须另立交接单执行(规划与执行分离)。


六、与既有档案的关系

档案 关系
71(兼容性预检:导入/上传即判定) 本档是其新增维度,机制与分级语义沿用,不替换
66(业务插件 P0 误报 → admin 显式信任) 本档 🟡 级沿用「放行 + 标注 + admin 可见」口径
70(anysearch 不兼容致崩溃循环) 同属「预检盲区导致线上事故」,本档是系统性补盲
74(实例内存治理:V8 堆限 256→160) §三 资源成本维度与 74 的配额治理同源

七、决策记录

  • 2026-09-12 · 用户提出「把这个作为插件评估和改造的一个点」→ 本档立标准
  • 待定:是否立即实现 §五 步骤 1–3(需另立交接单)