Skip to content

Test Core 的 Turbo 缓存有两条独立的失效机制,#5401 只覆盖了其中零条 —— 写入方 43% 被取消,且缓存键按 shard 分命名空间 #10228

Description

@os-elon

承接自 #10149 §4(测量卡已收口)。未认领,无 pm:* / domain:* 标签 —— 留给分诊定级与路由。

#5401 曾记录 Turbo 缓存的时序竞态,其方向 C(缓存池挤出)被明确留档、不在该单做,并预设了触发条件,逐字:

C(缓存池挤出假说,结构性解):留在本 issue 记录,不在本单做 …… 若 B 落地后同签名仍高频,以此为触发条件再议 C。

sharded test / dogfood 不在本单扩(它们在事故样本里自己的键链是命中的,无实测拉力;签名若再命中它们再补,一行一单)。

两条触发条件现在都满足了,而且量到的是两条 #5401 当时没有的机制。

机制一:缓存的唯一写入方有 43% 跑不完

Save Turbo cache (main only) 只在 main 的 push run 上执行。但 ci.yml 的 concurrency group 对 push 事件解析为 refs/heads/main —— 每次 main 推送共享同一个组,叠加 cancel-in-progress: true:

group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}cancel-in-progress: true

实测最近 30 次 push-to-main CI run:17 success / 13 cancelled(43%)。以一天 18+ 次落地、单 run 约 15 分钟的节奏,后一次落地几乎必然腰斩前一次。

⚠️ 这与 #5401 的分析是不同的机制:那份分析假设写入方正常完成、缓存代际被后来者从池里挤出(「每代约 12 个 job 键 × 250-300 MB ≈ 3 GB、池上限 10 GB」);这里是相当一部分代际根本没被写进去

⚠️ 注:该 concurrency 行为在 ci.yml 的注释里是有意设计(「an in-flight main run is cancelled only by a newer main push」)。所以这不是一个纯 bug,是一个当初的取舍在落地频率上升后产生了未被预期的副作用 —— 修法需要先回答「main 上那一轮 CI 到底是干什么用的」。

机制二:缓存键按 shard 分命名空间,三个 shard 的缓存各自独立老化

Test Core job 的 Turbo 缓存键把 matrix.shardgithub.job 一起插进键里。结合「只有 main push 写入」,后果是三个 shard 的缓存各自老化,而不是共享一份。

实测(同一 shard index 的不同腿):

runshardcached / total耗时
32233301407128 / 799m22s
20 / 8510m08s
331 / 7914m48s
32335265453181 / 834m48s
279 / 790m03s
32352993803131 / 798m18s
255 / 594m53s
333 / 8316m27s

同一条腿的区间是 866ms(79/79 命中,>>> FULL TURBO)到 10m08s(0/85 命中)。

为什么值得单独立卡

  1. 它是队列 run 间波动的主因。merge queue 关键路径回归:Test Core 最慢分片 16m28s、Dogfood 11m43s —— #4859 的两条验收判据均已不成立,且 #5401 方向 C 的触发条件已满足(实测) #10149 §1 那个「瓶颈每次换 shard」的签名,经排查是冷热对比而非分片变化:两次冷跑里长杆都是 shard 3。
  2. 它已经导致过一次错误诊断。merge queue 关键路径回归:Test Core 最慢分片 16m28s、Dogfood 11m43s —— #4859 的两条验收判据均已不成立,且 #5401 方向 C 的触发条件已满足(实测) #10149 §3 把一条 3 秒的腿读成「空桶」,实际是满载 24 个包、14551 个测试从热缓存重放。方法后果已写进 partition-test-shards.mjs 的头注释:单次构建的分片差不能当放置证据,要比就比同缓存状态的腿。
  3. 它与分片决策正交。merge queue 关键路径回归:Test Core 最慢分片 16m28s、Dogfood 11m43s —— #4859 的两条验收判据均已不成立,且 #5401 方向 C 的触发条件已满足(实测) #10149 的后继决策卡(阈值二选一)不论怎么走,这两条机制照样在。

未验证

候选方向(未定)

  1. 给 push 事件的 concurrency group 加 github.sha,让写入方跑完 —— 先要回答上面那个「main 那轮 CI 是干什么用的」。
  2. 给分片 job 补跨 job 缓存回退(merge_group 条目在前一次 main 合并后 ~4 分钟内入队时永远吃不到 Turbo 缓存 —— 连续合并每条多付数分钟冷构建(实测) #5401 预留的「一行一单」,PR chore(ci): lint.yml 的 typecheck 补 build-core 的 turbo 缓存回退 (#5401) #5542 已为 lint.yml 的 typecheck 做过逐字相同的改动)。
  3. 方向 C 本体:池容量 / remote cache。属 CI 基建 appetite。

关联

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions