Resolve #3591907 "Balance cypress E2E parallel split by runtime weight"
Closes #3591907
Cuts the slowest E2E node by ~25% on average (15–30% across runs). The improvement depends on the CI nodes assigned, but it's consistently faster feedback in any case.
What this MR does
ui/tests/support/parallel.js split the 46 Cypress E2E specs across the 4 CI nodes by
dealing them round-robin by filename — balancing spec count, not runtime. The heaviest
specs therefore stacked on whichever node the alphabetical order happened to fill (slowest
node ~21 min vs fastest ~7).
parallel.js now reads a // @canvas-ci weight=N flaky marker on the first line of a spec:
flakyspecs are dealt round-robin first, so no two share a node — bounding how much Cypress in-spec retries can inflate any single node.- the rest are bin-packed by
weight(relative runtime, one unit ≈ 30s; default 1) with a greedy longest-processing-time pass, spreading the heavy specs across nodes.
Weights are seeded from median durations measured across 5 recent 1.x pipelines. On the real
46 specs this takes the slowest node from ~21 min to ~14 min (4-node floor ≈ 12.5 min), at no
extra CI cost.
The exit 112 auto-retry guard in .gitlab-ci.yml previously hardcoded its own list of flaky
spec names. It now reads the flaky-tagged specs via ui/tests/support/flaky-specs.js, so the
markers are the single source of truth for both the split and the retry guard. The convention is
documented in docs/testing/gitlab-ci.md.
Testing steps
- Watch this MR's
cypress E2E 1/4…4/4job durations — they should land within a few minutes of each other, with no node far above the others. - Locally, confirm the split is balanced and complete:
Each node reports 10–13 specs, summing to 46.
cd ui && for i in 1 2 3 4; do CI_NODE_INDEX=$i CI_NODE_TOTAL=4 node tests/support/parallel.js | tr ',' '\n' | grep -c cy.js; done
Notes for reviewers
- No test logic changes — only a one-line marker comment added to 11 specs, the distribution
logic in
parallel.js, and the flaky-retry guard in.gitlab-ci.yml. - The guard previously hardcoded 4 flaky spec names; it now covers all
flaky-tagged specs (addscontextual-panelandprop-types, both observed retrying in the trace data), so a flaky failure in those retries the job instead of reddening the pipeline.
AI disclosure
Per Drupal.org's AI policy: the measurement (parsing 5 pipelines of CI traces), the balancing approach, and the initial weights were produced with AI assistance (Claude) and reviewed by a human before pushing.