Skip to content

ci: accelerate Playwright setup in CI#2700

Open
mroderick wants to merge 5 commits into
masterfrom
ci/playwright-cache-optimisation
Open

ci: accelerate Playwright setup in CI#2700
mroderick wants to merge 5 commits into
masterfrom
ci/playwright-cache-optimisation

Conversation

@mroderick

@mroderick mroderick commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Four independent changes to the CI workflow that reduce Playwright setup time per runner from ~23s to ~3s (on cache hit), and eliminate ~750MB of redundant cache storage.

Per-runner CI job drops from ~2m14s to ~2m. Aggregate runner time saved: ~137s per CI run.

Changes

1/4 — Share Playwright cache key across parallel runners

The cache key included ${{ matrix.ci_node_index }}, so each of the 6 parallel groups wrote and read its own cache entry for the same ~150MB Playwright binary (6× storage, 6× uploads).

Removes the node_index suffix. One cache entry shared by all groups.

Risk: None. The binary is the same regardless of which group restores it.

2/4 — Remove Playwright install-deps step

npx playwright install-deps chromium-headless-shell runs apt-get update and installs system packages. On ubuntu-24.04 every required system library (libasound2, libcairo2, libcups2, libnspr4, etc.) is already pre-installed. The only packages actually added were 9 font packages (CJK + xfonts, ~21MB) that are not needed for headless-shell rendering.

Removes the step, saves ~14s per runner.

Risk: Low. If a Playwright version bump introduces a new system library dependency, tests will fail with a clear error message, and the step can be re-added with run: npx --yes playwright@1.59.0 install-deps chromium-headless-shell.

3/4 — Cache ~/.npm for npx downloads

npx downloads the playwright npm package (~30MB) fresh every CI run, even on a cache hit for the binary. Caching ~/.npm means the package is restored from cache. On a cache hit the install step spends ~3s validating the existing binary instead of ~6s downloading.

Risk: None. Cache key includes the Playwright version — a bump invalidates it automatically.

4/4 — Skip Playwright install on cache hit

When the Playwright binary cache restores successfully, run a quick ls validation instead of the full npx install (~6s saved). Falls through to full install if the binary path is missing or corrupted.

Risk: Low. The ls fallback handles cache corruption gracefully.

Before/After (per runner, cache hit)

Step Before After
Cache Playwright browsers 3s 3s
Cache npx packages 0s (new, combined)
npx install chromium 6s — (skipped on hit)
Verify binary ~0s
install-deps 14s — (removed)
Total 23s ~3s

Pipeline wall clock (slowest runner): ~134s → ~120s (~10% faster)

Evaluation Guide

For the reviewer: verify these changes work by checking a CI run on this PR.

  1. Check each commit's diff — each is focused on one concern.
  2. CI results: after tests complete, open any runner's logs and find:
    • Cache hit for: npx-playwright-... — confirms the npx cache hit
    • Cache restored from key: playwright-Linux-chromium-headless-shell-1.59.0 — confirms the shared cache key
    • Cache hit occurred on the primary key... (no save) — confirms cache was reused
    • The Verify Playwright binary step runs and completes quickly
    • No Install Playwright system dependencies step exists
  3. Test pass rate: all 6 groups should pass. No regressions expected.
  4. Playwright feature tests still work: the capybara-playwright-driver should find the browser at ~/.cache/ms-playwright/... and run headless tests normally.

Estimated Impact

  • Per-runner: 23s → ~3s for Playwright setup (87% reduction)
  • Pipeline wall clock: ~14s faster (10% faster CI)
  • Cache storage: ~900MB → ~150MB (83% reduction)

Each of the 6 parallel CI groups was writing and reading its own cache
entry for the same ~150MB Playwright binary, because the cache key
included ci_node_index. This means 6x the storage and 6x the uploads
for the same content.

Remove the node_index suffix so all groups share one cache entry. The
first group to restore (or miss and write) populates the cache; the
other 5 restore from the same key.

Per-runner timing is unaffected (~3s restore either way). This eliminates
5 redundant uploads (~30s of upload time each, async after job completion)
and reduces GitHub Actions cache storage from ~900MB to ~150MB.
The install-deps step runs apt-get update and installs system packages.
On ubuntu-24.04, all required libraries (libasound2, libcairo2, etc.)
are already present. The only packages actually installed are 9 font
packages (CJK and X11 fonts, ~21MB) that aren't needed for headless-shell.

This step took ~14s per runner (6 runners = 85s aggregate). Removing it
saves ~14s of pipeline wall clock per CI run.

If a future Playwright version adds a new system library dependency,
re-add the step:
  run: npx --yes playwright@1.59.0 install-deps chromium-headless-shell
npx --yes playwright@1.59.0 downloads the playwright npm package (~30MB)
fresh each time before it even checks whether the binary is already cached.
Caching ~/.npm means the package is restored from cache. On a cache hit
the npx install step spends ~3s validating the existing binary instead of
~6s downloading + validating.

The cache key includes the Playwright version so a version bump triggers a
fresh download automatically.
On a cache hit, the chromium-headless-shell binary is already at
~/.cache/ms-playwright. Running npx --yes playwright install still
downloads the npm package and checks — wasteful when the binary exists.

When the Playwright cache restores successfully, run a quick ls check
instead of the full npx install (~6s saved). If the binary path is
missing or corrupted, fall through to the full install for safety.

On a cache miss (first run, version bump, or evicted entry), the
full npx install runs as before.
@mroderick

Copy link
Copy Markdown
Collaborator Author

Verified — both caches confirmed working

I ran two CI runs on this PR:

Run 1 (fresh caches, all missed)

The new cache keys had never been saved before, so:

  • npx-playwright-Linux-1.59.0 — cache miss, saved by Group 4 (now available for all)
  • playwright-Linux-chromium-headless-shell-1.59.0 — cache miss, saved by Group 4 (now available for all)

Even with cache misses, the install-deps removal alone saved ~80s aggregate across the 6 runners. All tests passed.

Run 2 (all caches hit, all 6 groups)

Results from the rerun:

Cache Status
npx-playwright-Linux-1.59.0 Hit for all 6 groups
playwright-Linux-chromium-headless-shell-1.59.0 Hit for all 6 groups
Verify Playwright binary step Ran for all 6 groups
Install Playwright step Did not run for any group
Install Playwright system dependencies Step removed, confirmed absent in all logs

Timing comparison

Metric Before After Saved
Playwright setup per runner (avg) ~23s ~8s 65%
Aggregate across 6 runners 137s 46s 66%
Pipeline wall clock (slowest) ~134s ~126s ~6%

The pipeline wall clock gain is modest because the critical path is now test execution time (48-104s per group depending on spec distribution), not Playwright setup. But Playwright setup is no longer a meaningful contributor — it completes in ~8s while the slower groups are still on earlier stages.

Cache storage impact

Instead of 6 separate cache entries for the same ~150MB binary (one per parallel group), there's now one shared entry. Estimated storage reduction: ~900MB to ~150MB.

@mroderick mroderick marked this pull request as ready for review July 10, 2026 10:22
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