Skip to content

ci: split surface unit tests into server and web jobs#625

Merged
gbasin merged 1 commit into
masterfrom
ci/split-surface-unit
Jul 21, 2026
Merged

ci: split surface unit tests into server and web jobs#625
gbasin merged 1 commit into
masterfrom
ci/split-surface-unit

Conversation

@gbasin

@gbasin gbasin commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

What / why

The combined Surface unit tests job runs the Postgres-backed server suite (the ~200s+ long pole) alongside the jsdom suites (web, mobile, shared, desktop, centaur-client) on one 4-vCPU runner. Server's 3 vitest workers compete for CPU with mobile's + web's, and the resulting starvation inflates server's wall time enough to trip the 6-minute step timeout on an otherwise-green suite — exactly what happened on #621 (909/909 tests passed, killed at 344s; a clean rerun ran the same tests in 205s).

This splits the server suite (keeps Postgres, own runner, 10-min step budget) from the DB-free jsdom suites (second runner, in parallel), and caps mobile's worker pool — it was the one heavy jsdom suite left uncapped, so it oversubscribed the shared runner. Verified only the server package touches Postgres, so the split is safe.

Measured, not assumed

Local A/B (10-core box, so contention is milder than CI — a lower bound) first ruled out the obvious lever: --workspace-concurrency=1 made total wall worse (195s → 272s, +40%) by de-overlapping the IO-bound server suite from the CPU-bound jsdom suites. But isolating the jsdom suites cut their test-time sharply (web 37s→16s, mobile 20s→9s), pinning the contention on CPU starvation.

Then measured on real 4-vCPU CI runners (this PR, 3 samples of the server job):

metric combined job (before) split: server (after)
server vitest wall ~205–344s 126.5 / 127.3 / 128.5s
server reported test-time 396s green · 915s on the timeout run 262 / 264 / 269s
step budget 6 min (tripped at 344s) 10 min (127s wall → huge headroom)
unit critical path (job wall) 4m33s, flaky to timeout 3m6s (server) ∥ 2m10s (web)

The point isn't just that it's faster — it's that server's variance collapsed from a 68% swing (205↔344s) to 1.6% (126.5↔128.5s) once it stops fighting the jsdom suites for cores. That swing was the flakiness. The web job (all jsdom suites, concurrent, mobile now capped) runs in ~75s of vitest wall on its own runner.

The combined "Surface unit tests" job ran the Postgres-backed server suite
(the ~200s+ long pole) alongside the jsdom suites (web, mobile, …) on one
4-vCPU runner. Server's 3 workers competed for CPU with mobile's + web's, and
the resulting starvation inflated server's wall time enough to trip the
6-minute step timeout on an otherwise-green suite (#621: 909/909 passed, killed
at 344s; a clean rerun did the same tests in 205s).

Measured the mechanism locally (10-core box, so contention is milder than CI):
serializing packages made total wall WORSE (+40%) by de-overlapping the
IO-bound server from the CPU-bound jsdom suites — so `--workspace-concurrency=1`
is the wrong lever. But isolating the jsdom suites cut their test time sharply
(web 37s→16s, mobile 20s→9s), confirming CPU starvation among them.

So: put the server suite on its own runner (keeps Postgres, 10-min step budget)
and the DB-free jsdom suites on a second runner in parallel. Also cap mobile's
worker pool (it was the one heavy jsdom suite left uncapped) to match web.

This is being pushed to measure the two jobs' real 4-vCPU times before it's
proposed as the fix.
@gbasin
gbasin added this pull request to the merge queue Jul 21, 2026
Merged via the queue into master with commit 07f7dca Jul 21, 2026
24 of 26 checks passed
@gbasin
gbasin deleted the ci/split-surface-unit branch July 21, 2026 05:04
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