Summary
Add a way to restore the store cache without saving it (e.g. cache: 'restore' alongside the boolean, or a separate cache-save: false input), and skip the post-step save entirely when the restore was an exact hit on the save key.
Problem
In a matrix workflow, every job that sets cache: true compresses and attempts to upload a full store copy in its post step. With v3's per-invocation save keys (runId-attempt-uuid), all N jobs in a run save successfully: N full store archives per run consuming the repository's 10 GB cache quota and evicting other entries, with only the freshest ever restored. Without the per-invocation suffix, as in #56's example, the saves instead race one exact key and all but one log Failed to save: Unable to reserve cache….
The toolkit already knows the answer in both cases:
- When the restored key equals the key the post step would save under (exact hit, unchanged lockfile), the upload can only fail or duplicate existing content. Skipping it costs nothing.
- When a caller knows the job should never publish (untrusted branch, fan-out job), there is no way to say "restore only".
cache: false disables the restore too, forcing a full network install.
Proposal
- Skip the save on an exact restore hit.
finalizeCache already computes cache-hit; the post step can compare the restored key against the save key prefix and no-op when the content is already published under an equivalent key.
- A
cache-save boolean input (default true) so workflows can run restore-only, matching actions/cache/restore + actions/cache/save, which exist precisely for this split, and GitHub's guidance to restrict cache writes to trusted triggers.
With both, a typical matrix goes from N post-step compressions and N saves (or N-1 warnings) to zero saves on warm runs and one save per platform on lockfile changes.
Context
Measured on an 11-job matrix (ubuntu/windows/macos, ~1-2 GB store): the post-step save costs 3-40s per job depending on platform (~130s of runner time per run in aggregate), all discarded on warm runs. Related: #55 (post step re-uploads a verification log the main step rejected), #56 (restore-only request, subsumed by this proposal).
Summary
Add a way to restore the store cache without saving it (e.g.
cache: 'restore'alongside the boolean, or a separatecache-save: falseinput), and skip the post-step save entirely when the restore was an exact hit on the save key.Problem
In a matrix workflow, every job that sets
cache: truecompresses and attempts to upload a full store copy in its post step. With v3's per-invocation save keys (runId-attempt-uuid), all N jobs in a run save successfully: N full store archives per run consuming the repository's 10 GB cache quota and evicting other entries, with only the freshest ever restored. Without the per-invocation suffix, as in #56's example, the saves instead race one exact key and all but one logFailed to save: Unable to reserve cache….The toolkit already knows the answer in both cases:
cache: falsedisables the restore too, forcing a full network install.Proposal
finalizeCachealready computescache-hit; the post step can compare the restored key against the save key prefix and no-op when the content is already published under an equivalent key.cache-saveboolean input (defaulttrue) so workflows can run restore-only, matchingactions/cache/restore+actions/cache/save, which exist precisely for this split, and GitHub's guidance to restrict cache writes to trusted triggers.With both, a typical matrix goes from N post-step compressions and N saves (or N-1 warnings) to zero saves on warm runs and one save per platform on lockfile changes.
Context
Measured on an 11-job matrix (ubuntu/windows/macos, ~1-2 GB store): the post-step save costs 3-40s per job depending on platform (~130s of runner time per run in aggregate), all discarded on warm runs. Related: #55 (post step re-uploads a verification log the main step rejected), #56 (restore-only request, subsumed by this proposal).