Skip to content

批 16:CI 构建缓存(owner 拍板)+ 两条 owner 拍板落档 #6

批 16:CI 构建缓存(owner 拍板)+ 两条 owner 拍板落档

批 16:CI 构建缓存(owner 拍板)+ 两条 owner 拍板落档 #6

Workflow file for this run

# 门禁(2026-08-21 批 13,owner 拍板:GitHub Actions 跑**全量**)
#
# ★ ★ ★ **这里只有一条命令,而且与本机那条逐字相同**:`bash tests/m0/docker-run.sh`。
# 这不是省事,是判据纪律:CI 若自己拼一套「等价的」步骤,就会长出**第二套判据**,
# 而两套判据迟早分家 —— 那时「CI 绿」与「门禁绿」是两件事,
# 却没有任何东西会说出来。本仓库为这个形状栽过好几次。
#
# ⚠ ⚠ **有意不写 `paths-ignore`。** 「只改文档就跳过 CI」看起来是白捡的省钱,
# 实际是错的:`crates/fulcrum-config/tests/doc_contract.rs` 用 `include_str!`
# 读 `docs/architecture/dsl-reference.md`,`crates/fulcrum/tests/supply_gates.rs`
# 读根 `Cargo.toml`/`Cargo.lock`,而批 11 那道门还反向断言
# **已接线的能力不许出现在 `dsl-reference.md` 里**。
# ⇒ **一次纯文档改动是真的能把门禁弄红的**,跳过它就等于把这类缺陷放行,
# 而现象是「CI 一直绿」。省钱要从别处省(见下面的 concurrency 与 timeout)。
#
# ⚠ **本仓库是私有仓库 ⇒ Actions 分钟数是计费的。** 两条止血阀都在下面:
# · `concurrency` + `cancel-in-progress`:连着推几次时,只有最后一次跑到底;
# · `timeout-minutes`:卡死的任务最多烧这么多,而不是默认的 6 小时。
name: gate
on:
# ★ 只在 main 上跑:owner 的口径是「直接提交 main,不开分支不开 PR」。
push:
branches: [main]
# 手工触发,用于改完 workflow 自身之后重跑。
workflow_dispatch:
concurrency:
group: gate-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
gate:
# ★ 钉住大版本,不用 `ubuntu-latest`:M1 的 systemd 场景依赖宿主机是 **cgroup v2**,
# 而 `ubuntu-latest` 换代时不会有任何一行输出告诉我们环境变了。
# 与 G36 钉构建镜像、Dockerfile.systemd 钉 systemd 版本是同一条纪律。
runs-on: ubuntu-24.04
# 冷缓存下要整编 pingora fork + 全部依赖,再跑十四个场景。
# ⚠ 这个上限是**计费止血阀**,不是预期耗时;真实耗时见每次运行的记录。
timeout-minutes: 120
steps:
- uses: actions/checkout@v4
# ★ ★ runner 上 `/` 只有二十几 GB 空余,而这里要放:rust 构建镜像、
# systemd 测试镜像、cargo registry、**release 模式的整个 target**。
# ⚠ 磁盘满的报错形态五花八门(链接器 OOM、docker 写层失败),
# 而没有一条会说「磁盘满了」。先腾出来,比事后猜便宜。
- name: 腾出磁盘
run: |
echo "── 清理前 ──"; df -h /
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \
/usr/local/share/boost /usr/local/.ghcup "$AGENT_TOOLSDIRECTORY" || true
echo "── 清理后 ──"; df -h /
# ★ 每次都把环境打出来。§8 要求可复现,而可复现的第一步是**看得见跑的是什么**。
# ⚠ cgroup 那一行是判据相关的:M1 的 `ExitType=cgroup` 要求容器侧 systemd ≥ 250
# 且宿主机是 cgroup v2 统一层级。它变成 v1 的那天,M1 场景会以一种
# 看起来像产品缺陷的方式红。
- name: 环境快照
run: |
echo "── docker ──"; docker version
echo "── 内核 ──"; uname -a
echo "── cgroup 层级 ──"; stat -fc %T /sys/fs/cgroup
echo "── git 行尾配置(CRLF 门的前提)──"
git config --get core.autocrlf || echo "core.autocrlf 未设(Linux 上的默认,正是要的)"
# ── 构建缓存(owner 2026-08-21 拍板加)─────────────────────────────
#
# ★ 实测数字(本机量的):`fulcrum-cargo` 684MB、`fulcrum-target-*` **6.3GB**
# (vendor 3.0G + debug 2.8G + release 580M);抽样压缩比 gzip -1 已有 2.8x,
# zstd 更高 ⇒ 归档约 2GB 上下,装得进 GitHub 每仓 10GB 的缓存预算。
# ★ 冷缓存下一次全量 CI 实测 **21m44s**(32441478101,第一次全绿的那次)。
#
# ⚠ ⚠ **缓存最坏的失效方式不是「没命中」,是「命中了一份不该用的」。**
# 两道防线:① 键里带 `Dockerfile.build` 的哈希(工具链身份,连 C 工具链一起);
# ② `tests/ci/cache.sh` 在归档里另存一份 meta,**灌回前逐字比对**,
# 对不上就跳过并说明,绝不硬灌。
#
# ★ **怀疑缓存的时候怎么办**:把下面键里的 `v1` 改成 `v2`,整片缓存立即作废。
- name: 取构建缓存
id: buildcache
uses: actions/cache/restore@v4
with:
path: ~/fulcrum-cache
# ★ 精确键 = 工具链 + 两把锁。锁变了就换一份新缓存,
# 而 restore-keys 让它仍然能从**同一套工具链**的上一份热起来(cargo 增量补差)。
key: fulcrum-buildcache-v1-${{ runner.os }}-${{ hashFiles('docker/Dockerfile.build') }}-${{ hashFiles('Cargo.lock', 'vendor/pingora/Cargo.lock') }}
restore-keys: |
fulcrum-buildcache-v1-${{ runner.os }}-${{ hashFiles('docker/Dockerfile.build') }}-
- name: 把缓存灌回 docker 卷
run: bash tests/ci/cache.sh restore ~/fulcrum-cache
# ★ ★ ★ 就这一条。与 AGENTS.md「Current validation」第 3 条、
# 与每份交接单里写的那条命令,**逐字相同**。退出码就是判据。
# ⚠ 绝不接管道:`| tee` / `| tail` 取回的是右边那个命令的退出码(本仓库栽过)。
- name: 全量门禁(十四场景)
run: bash tests/m0/docker-run.sh
# ★ `always()`:门禁红了也要存 —— 依赖照样是编好的,下一次能省下同样多的时间。
# ⚠ 而**精确命中时不重存**(`cache-hit != 'true'`):那 2GB 上传是纯浪费。
- name: 导出构建缓存
if: always()
run: bash tests/ci/cache.sh save ~/fulcrum-cache
- name: 存构建缓存
if: always() && steps.buildcache.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: ~/fulcrum-cache
key: fulcrum-buildcache-v1-${{ runner.os }}-${{ hashFiles('docker/Dockerfile.build') }}-${{ hashFiles('Cargo.lock', 'vendor/pingora/Cargo.lock') }}