协议线 PM 会话在 v17 窗口连推 spec PR 时观测到的高频基建 flake,不是任何一个 PR 的内容问题。只记录证据与分析,不自行改 CI 配置(影响面是全仓所有 PR,且同时段有另一个 PM 会话在跑)。
现象:两个内容完全无关的 PR,同一步、同一签名
| PR |
内容 |
CJS/ESM |
失败点 |
同 job 测试 |
#4831 (4f136c55) |
activationEvents 退役(纯删除) |
✅ Build success in 17882ms |
DTS Build start → ELIFECYCLE Command failed. |
7358 test(s) declared and all 7358 accounted for |
#4841 (f3e2f404) |
batch 行结果形状迁移 |
✅ Build success in 18043ms |
DTS Build start → ELIFECYCLE Command failed. |
7362 test(s) declared and all 7362 accounted for |
两者都是 Test Core (1/2),耗时同为 ~1m40s。关键特征:
分析:堆上限设得比 runner 物理内存还接近
packages/spec/package.json:
build: pnpm gen:schema && pnpm gen:openapi && tsup && \
if [ -z "$OS_SKIP_DTS" ]; then NODE_OPTIONS="--max-old-space-size=12288" BUILD_DTS=true tsup; fi
tsup.config.ts 里的注释写着 // Generate DTS separately to avoid memory issues —— 拆开单跑本身是对的处置,但那一趟给了 12288 MB(12 GB) 的老生代上限。
.github/workflows/ci.yml 的 Test Core 是 runs-on: ubuntu-latest,公开仓标准 runner 为 4 vCPU / 16 GB。
--max-old-space-size 是告诉 V8 可以涨到多少,不是预留。设成 12 GB 意味着 V8 在逼近 12 GB 之前不会激进 GC;叠加 tsup/tsc 自身的堆外内存、pnpm/turbo 进程与系统占用,总量越过 16 GB 物理内存时,内核先于 V8 的 OOM 处理把进程杀掉 —— 于是没有任何 Node 侧的错误输出。
也就是说:这个设置在 16 GB runner 上不是防 OOM,而是 OOM 的成因之一。随着 spec 类型图增长,越界从偶发变成了几乎每次首跑必现。
为什么现在才密集出现
turbo 对 @objectstack/spec#build 有缓存,只有改动 spec 的 PR 才真正跑这一趟。v17 窗口内 spec PR 密集,于是暴露频率陡增。非 spec PR(如 #4823)命中缓存,完全看不到这个问题。
可能的处置方向(供维护者裁决,未实施)
- 调低 DTS 堆上限到与物理内存相称(如
--max-old-space-size=8192 甚至 6144),让 V8 在越过物理内存前先积极 GC —— 反直觉但通常正是修法;
- 给 DTS 步骤换更大的 runner(
runs-on: ubuntu-latest-8-cores 之类,若组织有配额);
- 进一步拆分 DTS 入口(现在 16 个入口一趟出),按入口分批;
- 三者可组合。
任一方向都建议先复现再改:在 CI 上跑一次带 /usr/bin/time -v 或 --max-old-space-size 探测的 job,拿到真实峰值 RSS,再定数字 —— 否则又是一次凭猜调参。
影响
不阻塞合并(重跑可过),但让每个 spec PR 多花一轮 CI,在发布窗口期是实打实的节流。协议线目前还有 #4756 / #4709 / #4001 / #4391 四个 spec 单在飞,预计都会命中。
关联:#4831、#4841、#4796(另一个已知 flaky,spec/src/cloud/tenant.test.ts 5s 超时,与本条无关)。
Generated by Claude Code — session session_0176qgxgCXTJCUv4YFLtusP9
协议线 PM 会话在 v17 窗口连推 spec PR 时观测到的高频基建 flake,不是任何一个 PR 的内容问题。只记录证据与分析,不自行改 CI 配置(影响面是全仓所有 PR,且同时段有另一个 PM 会话在跑)。
现象:两个内容完全无关的 PR,同一步、同一签名
4f136c55)Build success in 17882msDTS Build start→ELIFECYCLE Command failed.7358 test(s) declared and all 7358 accounted forf3e2f404)Build success in 18043msDTS Build start→ELIFECYCLE Command failed.7362 test(s) declared and all 7362 accounted for两者都是
Test Core (1/2),耗时同为 ~1m40s。关键特征:DTS Build start的下一行直接是ELIFECYCLE。这是进程被 SIGKILL 的签名(编译错误会打印诊断,内存耗尽的 V8 会打印 heap OOM 堆栈;两者都没有 = 被内核 OOM-killer 杀掉)。check-test-completeness在两个 job 里都报 OK,说明测试阶段完整跑完,失败纯在构建。rerun_failed_jobs后转绿并进入合并队列。故是边际性问题,不是确定性失败。分析:堆上限设得比 runner 物理内存还接近
packages/spec/package.json:tsup.config.ts里的注释写着// Generate DTS separately to avoid memory issues—— 拆开单跑本身是对的处置,但那一趟给了 12288 MB(12 GB) 的老生代上限。.github/workflows/ci.yml的Test Core是runs-on: ubuntu-latest,公开仓标准 runner 为 4 vCPU / 16 GB。--max-old-space-size是告诉 V8 可以涨到多少,不是预留。设成 12 GB 意味着 V8 在逼近 12 GB 之前不会激进 GC;叠加 tsup/tsc 自身的堆外内存、pnpm/turbo 进程与系统占用,总量越过 16 GB 物理内存时,内核先于 V8 的 OOM 处理把进程杀掉 —— 于是没有任何 Node 侧的错误输出。也就是说:这个设置在 16 GB runner 上不是防 OOM,而是 OOM 的成因之一。随着 spec 类型图增长,越界从偶发变成了几乎每次首跑必现。
为什么现在才密集出现
turbo对@objectstack/spec#build有缓存,只有改动 spec 的 PR 才真正跑这一趟。v17 窗口内 spec PR 密集,于是暴露频率陡增。非 spec PR(如 #4823)命中缓存,完全看不到这个问题。可能的处置方向(供维护者裁决,未实施)
--max-old-space-size=8192甚至 6144),让 V8 在越过物理内存前先积极 GC —— 反直觉但通常正是修法;runs-on: ubuntu-latest-8-cores之类,若组织有配额);任一方向都建议先复现再改:在 CI 上跑一次带
/usr/bin/time -v或--max-old-space-size探测的 job,拿到真实峰值 RSS,再定数字 —— 否则又是一次凭猜调参。影响
不阻塞合并(重跑可过),但让每个 spec PR 多花一轮 CI,在发布窗口期是实打实的节流。协议线目前还有 #4756 / #4709 / #4001 / #4391 四个 spec 单在飞,预计都会命中。
关联:#4831、#4841、#4796(另一个已知 flaky,
spec/src/cloud/tenant.test.ts5s 超时,与本条无关)。Generated by Claude Code — session
session_0176qgxgCXTJCUv4YFLtusP9