Skip to content

ci: cache Composer downloads, so a codeload outage stops taking the build down - #23

Merged
datlechin merged 1 commit into
mainfrom
ci/cache-composer
Aug 17, 2026
Merged

ci: cache Composer downloads, so a codeload outage stops taking the build down#23
datlechin merged 1 commit into
mainfrom
ci/cache-composer

Conversation

@datlechin

Copy link
Copy Markdown
Member

Every PHP job downloads its dependencies from scratch on every run. npm has been cached since these workflows were written; Composer never was.

When GitHub's codeload started answering 429 this afternoon, all three PHP jobs died at "Install PHP dependencies" before a single test executed:

Failed to download symfony/polyfill-intl-normalizer from dist: ... (HTTP/2 429)
Failed to download pestphp/pest-plugin-laravel from dist: ... (HTTP/2 429)
Source fallback is disabled. Not trying alternative sources.
##[error]Process completed with exit code 100.

108 rate-limit responses, zero assertions run — on a commit verified green locally (168 tests, 2139 assertions).

What it caches, and why not vendor/

The Composer files directory, not vendor/. The files cache holds the downloaded archives, so composer install still resolves and extracts normally and can't be fooled by a partially restored vendor tree — it just finds every archive on disk instead of reaching for the network.

- name: Resolve the Composer cache directory
  id: composer-cache
  run: echo "dir=$(composer config cache-files-dir)" >> "$GITHUB_OUTPUT"

- name: Cache Composer downloads
  uses: actions/cache@v4
  with:
    path: ${{ steps.composer-cache.outputs.dir }}
    key: composer-${{ runner.os }}-${{ hashFiles('composer.lock') }}
    restore-keys: composer-${{ runner.os }}-

Keyed on composer.lock so a dependency change invalidates it exactly, with a restore-key so a changed lock still reuses every archive that didn't move and fetches only the delta.

Where it's applied

All four install sites — both jobs in tests.yml, plus lint.yml and og.yml — each placed after setup-php, so composer is on PATH when the cache directory is resolved. Verified for every file:

workflow setup-php cache step install
tests.yml (php matrix) 27 35 45
tests.yml (ssr) 91 105 115
lint.yml 23 30 40
og.yml 34 46 56

The key deliberately omits the PHP version: the matrix jobs download identical archives, so 8.4 and 8.5 share one cache rather than warming two.

What this does not do

It does not rescue a cold cache. The first run after this merge still has to download, and will still fail if the incident is ongoing. It stops the second one from depending on GitHub being healthy.

If you'd rather also survive a cold-cache outage, the next lever is a bounded retry around composer install — I left that out because it also masks genuine failures, and it's a separate call from the one you made.

…uild down

Every PHP job downloads its dependencies from scratch on every run. npm has
been cached since the workflows were written; Composer never was. When GitHub's
codeload started answering 429 this afternoon, all three PHP jobs died at
"Install PHP dependencies" before a single test executed — 108 rate-limit
responses and zero assertions run, on a commit that was green locally.

Caches the Composer files directory rather than vendor/. The files cache holds
the downloaded archives, so `composer install` still resolves and extracts
normally and cannot be fooled by a partially restored vendor tree; it simply
finds every archive on disk instead of reaching for the network.

Keyed on composer.lock, so a dependency change invalidates it exactly, with a
restore-key so a changed lock still reuses every archive that did not move and
only fetches the delta.

Applied at all four install sites: both jobs in tests.yml, plus lint.yml and
og.yml, each placed after setup-php so composer is on PATH when the cache
directory is resolved. The key deliberately omits the PHP version — the matrix
jobs download identical archives, so 8.4 and 8.5 share one cache.

This does not rescue a cold cache: the first run after this merge still has to
download, and will still fail if the incident is ongoing. It stops the second
one from depending on GitHub being healthy.
@datlechin
datlechin merged commit 182a035 into main Aug 17, 2026
2 of 10 checks passed
@datlechin
datlechin deleted the ci/cache-composer branch August 17, 2026 15:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant