ci: key the e2e build cache on its entries, cache Gradle, drop the pnpm store cache - #909
Merged
Merged
Conversation
janicduplessis
added this pull request to stack #906
September 19, 2026 12:56
…pm store cache Closes #904.
…full entries in the build cache key
janicduplessis
force-pushed
the
@janic/ci-cache-audit
branch
from
September 20, 2026 00:08
7e0c4ac to
c829083
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
The repository's Actions cache is at 10.35 GB across 70 entries, past the 10 GB limit, so GitHub is already evicting least-recently-used entries. Audit of the last 20 executed Native E2E runs and 20 CI runs (9/12 to 9/19), from the job logs and the caches API:
pnpm/setupcache: true)pnpm-cache-Linux-x64-<lockfile hash>pnpm install4 to 6 s with the store, 4.4 to 5.1 s cold (reused 0, downloaded 1314)pnpm-cache-Windows-x64-<hash>pnpm-cache-macOS-arm64-<hash>setup-nodecache: pnpm)node-cache-Linux-x64-pnpm-<hash>STIM_BUILD_CACHE)stim-cli-buildcache-<platform>-<framework>-<lockfile hash>+ prefix restore-keysactions/cachesaves only on an exact-key miss, so each entry froze at the first save per lockfile hash while the generated fixture's fingerprint moved (daily on ios-bare). 10 entries (1 GB) were saved fromqa/*dispatch branches, unreadable by main~/.gradle)Configure project :app; Linux cold build 4m08 to 6m12 versus 3m37 in the same job with dependencies presentmodules-2+wrapperpod install1m35 total; the Hermes/ReactNativeCore/Dependencies downloads take about 6 screate-expo-app,cli init@latestcancel-in-progressSolution
Drop the pnpm store cache on every lane (
cache: falseinsetup-stim, nocache: pnpminruntime-floor,docs.yml). It was 8 GB of the budget for no measurable install time.Rekey the build cache on its contents. Nothing in the repository predicts the generated fixture's fingerprint, so the restore uses the lane prefix alone and
restore-keyspicks the newest entry. After the suite,scripts/e2e-build-cache.mjstrims the directory to the two newest fingerprints per platform and names them in the key (stim-cli-buildcache-v2-ios-expo-<fp1>-<fp2>);actions/cache/saveruns only when that key differs from the restored one, so an unchanged fixture saves nothing and a moved fingerprint saves one entry, with the previous one expiring 7 days later. Onlymainsaves. Pull requests restore main's entry and never save, because GitHub scopes an entry to the ref that saved it. The detect step printsbuild cache: HIT <key>orbuild cache: MISSand derivesSTIM_E2E_WARM_CACHEfromcache-matched-key.Cache Gradle on the Android lanes.
~/.gradle/caches/modules-2and~/.gradle/wrapper(the two directories the caches suite seeds its throwaway home from) on Linux and Windows undergradle-v1-<os>-<framework>-<yyyy-mm>with a prefix restore-key: the first main run of each month refreshes the entry from the previous one. Like the build cache it saves frommainonly, and not from the caches suite, which never writes to the real Gradle home;modules-2.lockandgc.propertiesare excluded because the daemon holds the lock open and that fails the archive on Windows (actions/setup-java#633). Entry size is an estimate (0.7 to 1 GB) until the first run reports it.Expected outcome:
mainsaves either, so pull requests add nothing. Under 4 GB typical; the worst overlap can touch the 10 GB limit, and what LRU evicts then is a stale archive nothing restores.e2e-smoke/e2e-looplabeled pull request).Test plan
pnpm test scripts/e2e-build-cache.test.mjs: keeps the two newest entries per platform, drops older ones and*.staging-*leftovers, keys an unchanged set identically and a changed set differently, no key for an empty root.node scripts/e2e-build-cache.mjs /tmp/bc stim-cli-buildcache-v2-ios-expoon a hand-made root printedkey=stim-cli-buildcache-v2-ios-expo-aaaa1111aaaaand removed the staging directory.The full check set (
format:check,lint,build,typecheck,knip,test) passes.The rekeying is only fully verifiable after merge: on this branch (
e2e-smokelabel) the Android jobs should logCache not found for input keys: gradle-v1-...and the build cachebuild cache: MISS, with no save of either; the first main run should savegradle-v1-*andstim-cli-buildcache-v2-*entries, the latter naming at most two fingerprints, and the nightly after it should logbuild cache: HITandwt1 warm-started from the cross-run cache.Total size, to read after the first nightly:
The 70 existing entries stop being requested and expire after 7 days;
gh api -X DELETE "repos/appandflow/stim/actions/caches?key=<key>"clears one sooner.Fixes #904.