From d712af3f59f71f23ef86f678240790d7f8d80ea0 Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Wed, 8 Jul 2026 10:58:55 -0400 Subject: [PATCH] =?UTF-8?q?ci:=20fix=20cargo=20cache=20eviction=20?= =?UTF-8?q?=E2=80=94=20rust-cache,=20per-suite=20e2e=20keys,=20main-only?= =?UTF-8?q?=20saves?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every ubuntu e2e leg has been cold-compiling the full ~275-crate graph on every PR run. Two compounding causes: 1. Matrix key collision: all ~9 same-OS e2e legs shared one cache key (`-cargo-e2e-`), so a single leg won the cache reserve per run and the other 8 logged "Unable to reserve cache". 2. Budget blowout: caching the entire target/ dir put a single main run's cache footprint at ~8.2 GiB (windows 3.96 GB, macos 2.19 GB) against GitHub's 10 GiB LRU budget, so PR-branch saves evicted the main caches (and vice versa) — the big e2e caches always first. Fix: swap the five raw actions/cache blocks (clippy, test matrix, test-release, coverage, e2e) for Swatinem/rust-cache, which prunes the cache to dependency artifacts (~5-10x smaller) and keys on the rustc host triple + job automatically; give e2e legs a per-suite key; and restrict saves to main (`save-if`) so PR branches restore without churning the budget. Workspace crates recompile per run by design — that's the ~1-2 min tradeoff that keeps dependency caches alive. The docker-image jobs keep their deliberate no-cache stance (zizmor cache-poisoning audit). Co-Authored-By: Claude Fable 5 --- .github/workflows/ci.yml | 85 +++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5bc8ca9..25805c1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,14 +25,16 @@ jobs: run: rustup show - name: Cache cargo - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + # Swatinem/rust-cache instead of a raw actions/cache of the whole + # target/ dir: it prunes the cache to dependency artifacts (~5-10x + # smaller), which keeps this repo's total cache footprint inside + # GitHub's 10 GiB budget — previously a single main run produced + # ~8 GiB of caches and every PR save evicted them (cold e2e legs + # recompiled the full ~275-crate graph each run). save-if restricts + # writes to main so PR branches restore without churning the budget. + uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ubuntu-latest-cargo-clippy-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ubuntu-latest-cargo-clippy- + save-if: ${{ github.ref == 'refs/heads/main' }} - name: Run clippy run: cargo clippy --workspace --all-features -- -D warnings @@ -82,14 +84,16 @@ jobs: run: rustup show - name: Cache cargo - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + # Swatinem/rust-cache instead of a raw actions/cache of the whole + # target/ dir: it prunes the cache to dependency artifacts (~5-10x + # smaller), which keeps this repo's total cache footprint inside + # GitHub's 10 GiB budget — previously a single main run produced + # ~8 GiB of caches and every PR save evicted them (cold e2e legs + # recompiled the full ~275-crate graph each run). save-if restricts + # writes to main so PR branches restore without churning the budget. + uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ matrix.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ matrix.os }}-cargo- + save-if: ${{ github.ref == 'refs/heads/main' }} - name: Build run: cargo build --workspace --all-features @@ -138,14 +142,16 @@ jobs: run: rustup show - name: Cache cargo - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + # Swatinem/rust-cache instead of a raw actions/cache of the whole + # target/ dir: it prunes the cache to dependency artifacts (~5-10x + # smaller), which keeps this repo's total cache footprint inside + # GitHub's 10 GiB budget — previously a single main run produced + # ~8 GiB of caches and every PR save evicted them (cold e2e legs + # recompiled the full ~275-crate graph each run). save-if restricts + # writes to main so PR branches restore without churning the budget. + uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ubuntu-latest-cargo-release-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ubuntu-latest-cargo-release- + save-if: ${{ github.ref == 'refs/heads/main' }} - name: Run tests (release) run: cargo test --workspace --all-features --release @@ -181,14 +187,16 @@ jobs: tool: cargo-llvm-cov@0.8.7 - name: Cache cargo - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + # Swatinem/rust-cache instead of a raw actions/cache of the whole + # target/ dir: it prunes the cache to dependency artifacts (~5-10x + # smaller), which keeps this repo's total cache footprint inside + # GitHub's 10 GiB budget — previously a single main run produced + # ~8 GiB of caches and every PR save evicted them (cold e2e legs + # recompiled the full ~275-crate graph each run). save-if restricts + # writes to main so PR branches restore without churning the budget. + uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ubuntu-latest-cargo-coverage-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ubuntu-latest-cargo-coverage- + save-if: ${{ github.ref == 'refs/heads/main' }} - name: Run tests with coverage # Two-step pattern: `--no-report` runs instrumented tests and @@ -519,14 +527,19 @@ jobs: run: rustup show - name: Cache cargo - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ matrix.os }}-cargo-e2e-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ matrix.os }}-cargo-e2e- + # Swatinem/rust-cache instead of a raw actions/cache of the whole + # target/ dir: it prunes the cache to dependency artifacts (~5-10x + # smaller), which keeps this repo's total cache footprint inside + # GitHub's 10 GiB budget — previously a single main run produced + # ~8 GiB of caches and every PR save evicted them (cold e2e legs + # recompiled the full ~275-crate graph each run). save-if restricts + # writes to main so PR branches restore without churning the budget. + uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + with: + # Matrix suites otherwise collide on one key: only one of the ~9 + # same-OS legs wins the cache reserve and the rest fail to save. + key: ${{ matrix.suite }} + save-if: ${{ github.ref == 'refs/heads/main' }} - name: Setup Node.js if: matrix.suite == 'e2e_npm' || matrix.suite == 'e2e_scan' || matrix.suite == 'e2e_safety_pnpm'