warm_cache: only delete the caches of the ref it runs on - #83
Open
oliviermattelaer wants to merge 1 commit into
Open
warm_cache: only delete the caches of the ref it runs on#83oliviermattelaer wants to merge 1 commit into
oliviermattelaer wants to merge 1 commit into
Conversation
The refresh jobs delete a cache before saving it, because actions/cache never
overwrites an existing key. The delete was written without --ref, and
`gh cache delete <key>` matches the key across every ref unless one is given,
so a refresh deletes the copy held by every branch, not just its own.
The save is ref scoped, so what comes back exists only under the ref that ran
the workflow. That is fine on main, whose caches every branch can read, and
destructive anywhere else: the shared copy is gone and the replacement is
visible only to the branch that made it. With fail-on-cache-miss set on the
restore actions, every other branch then fails before running a test.
That is not hypothetical. A manual dispatch on madspin_branch left
heptools-ubuntu24, delphes-ubuntu24 and root-ubuntu24 held solely by
refs/heads/madspin_branch, and every branch except that one failed on
Failed to restore cache entry. Exiting as fail-on-cache-miss is set.
Input key: heptools-ubuntu24
The ref guard on the refresh job does not prevent it: workflow_dispatch and
schedule are accepted from any branch, by design, so that a cache can be
rebuilt without pushing to main.
Pass --ref "${{ github.ref }}" to all thirteen live deletes. A refresh now
replaces only what its own ref holds, and a dispatch on a feature branch gives
that branch its own copy while leaving the main-scoped one intact. The two
commented-out deletes are left as they are.
warm_cache never runs on a pull_request event -- only push, schedule and
workflow_dispatch -- so github.ref is always refs/heads/<branch> here.
Note this does not repair the current state: a run on main is still needed to
recreate the main-scoped caches that the madspin_branch dispatch removed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
The problem
The cache-refresh jobs delete a cache before saving it, since
actions/cachenever overwrites an existing key. The deletes were written without--ref:gh cache delete heptools-${{ env.CACHE_KEY }} --repo $GITHUB_REPOSITORY || truegh cache delete <key>matches the key across every ref unless one is given —--refexists precisely to narrow it, and the REST API documentsrefas an optional restriction on an otherwise key-wide delete.The save, by contrast, is ref-scoped. So a refresh deletes every branch's copy and puts back one visible only to the ref that ran it. On
mainthat is harmless, because every branch can read a default-branch cache. Anywhere else it is destructive.It already happened
A manual dispatch on
madspin_branchleft the shared caches held solely by that branch:With
fail-on-cache-miss: trueon the restore actions, every branch except that one then failed before running a single test:On one branch that took out four workflows — acceptance (mg7), acceptance (madevent), acceptance (rest) and parallel — while
madspin_branchitself stayed green, which is what makes the cause easy to misread as a code regression.That the delete is responsible, rather than the save, is visible in the cache list: 12 other keys are currently held under several refs at once (one
madspace-*key exists underrefs/heads/main,refs/heads/madnis-paperandrefs/pull/68/mergesimultaneously). Saving on a branch does not displace another branch's copy — soheptools-ubuntu24surviving under one ref only means the others were deleted.The existing ref guard does not prevent this, and shouldn't have to:
workflow_dispatchandscheduleare deliberately accepted from any branch, so a cache can be rebuilt without pushing tomain.The change
Pass
--ref "${{ github.ref }}"to all thirteen live deletes. A refresh then replaces only what its own ref holds: onmainit behaves exactly as before, and a dispatch on a feature branch gives that branch its own copy while leaving the main-scoped one intact.warm_cachenever runs on apull_requestevent — onlypush,scheduleandworkflow_dispatch— sogithub.refis alwaysrefs/heads/<branch>here. The two commented-out deletes are left alone. YAML re-parses; 13 insertions, 13 deletions.Alternative considered
Tightening the guard so
workflow_dispatch/schedulealso requiremain. Rejected: it removes the ability to rebuild a cache from a branch, and it leaves the sharp edge in place for whoever re-adds that ability later. Scoping the delete makes the damage structurally impossible instead.Not fixed by this PR
The caches are still in the broken state. This change prevents recurrence; it does not repair what the earlier dispatch removed. A
warm_cacherun onmainis needed to recreate the main-scoped copies, after which the failed jobs on other branches will pass on re-run.