Repository navigation
CI perf (settings): merge queue builds 5 entries at a time — a 13-PR burst took 100 min to drain on a 21-min CI run (~21 min per PR past the 5th) #1248
Description
Filed by the CI profiler routine (observer only). This is a ruleset change, so a human has to decide; the implementer routine can't apply it.
Measurement
Window: 2026-10-08 08:17 → 2026-10-09 08:17 UTC. Sources: ruleset 24668460, 157 CI merge_group runs, job detail for 52 of them, and REST timelines of the 14 most recently merged PRs.
Current merge_queue rule: max_entries_to_build: 5, max_entries_to_merge: 5, min_entries_to_merge: 1, grouping_strategy: ALLGREEN, check_response_timeout_minutes: 120.
| metric | value |
|---|---|
| PRs merged / 24h | 69 |
merge_group CI success, created → done, p50 / p90 |
23.4 / 46.1 min (n=80); 21.5 / 23.0 min since 04:17 (n=16) |
| Last enqueue → merge, p50 / p90 (14 PRs merged 03:14–08:01) | 64 / 69 min |
| First enqueue → merge, p50 / p90 | 65 / 82 min |
What happened in the 06:19–08:01 burst. 13 PRs were enqueued between 06:19 and 06:52: #1215, #1209, #1208, #1217, #1193, #1218, #1036, #1041, #1226, #1230, #1229, #1228, plus #1007. They were tested in waves of at most 5 CI runs, and each wave started only after the previous one finished:
| wave created | runs | outcome |
|---|---|---|
| 06:19–06:20 | 5 | all cancelled. test (windows-latest, 1) failed in 37892957346 and evicted #1215; the other 4 were rebuilds (37892958452 etc.) |
| 06:34–06:35 | 5 | 2 ok, 3 cancelled (coverage-docker (sbt) failure in 37894279963) |
| 06:56 | 5 | all ok → merged 06:56 / 07:19 |
| 07:17–07:19 | 5 | all ok → merged 07:38–07:41 |
| 07:38–07:41 | 4 (+1 cancelled) | merged 08:01 |
So the queue's throughput is 5 PRs per ~21 min (≈14/h). The 6th–13th PRs of a burst wait one or two full waves before their own run even starts. Of the 64-min p50, about 21 min is the PR's own run and ~40 min is waiting behind earlier waves.
Where the time goes
- Per wave:
test (windows-latest, 2)(Run tests 15.0 min p50 + Build 2.2),coverage-docker (sbt)→coverage-merge(CI perf: coverage-docker (sbt) — 5.6-min image rebuild warms 3 unused toolchains; merge-queue critical path (~2.5 min/merge-group run) #1225), and the Gradlee2e_redirect_gradle_build … gradle_hosted_blegs (13.4 min p50, CI perf: Gradle e2e shards unbalanced — b-p leg is the merge-queue critical path (~3 min/merge-group run) #1171) all finish at 20–22 min. Queue wait for those jobs is ≤0.1 min (Linux/Windows) and 0.2 min p50 (macOS), so the waves are not runner-starved. The limit is the build depth. - Rebuild cost when an entry is evicted (52-run sample):
- 15 runs cancelled purely as rebuilds behind an evicted entry: 4,311 job-min, 287 avg
- 10 runs with a genuine failure: 4,110 job-min
- 27 successful runs: 12,795 job-min, 474 avg
- A deeper build window raises the first number.
Root cause
max_entries_to_build: 5 caps the speculative pipeline at 5 entries. With ALLGREEN groups of up to 5 and every wave taking about the same ~21 min, the queue advances in lock-step waves. During the agent bursts that now produce most merges, every PR past the 5th waits at least one extra full wave.
Proposed fix (ruleset 24668460, merge_queue rule)
- Raise
max_entries_to_build5 → 8, and keepmax_entries_to_mergeat 5 (or raise it to 8 too, so a fully green window lands in one merge). - Leave
grouping_strategy, timeouts and the required checks (ci-ok,clippy) unchanged. - Roll back if any of these hold over the following 24h:
- macOS job queue-wait p90 goes above ~5 min (it is 1.8 min now)
- the merge_group eviction rate stays above ~20%. Then the extra rebuilds cost more than the latency buys; prefer landing the ci-janitor flake fixes (Fix Windows flake in read-set replacement test #1237, Retry HTTP errors in sbt/composer Docker image downloads #1238, Retry Docker e2e maven/cargo fixture fetches past registry blips #1222, Retry Bun backtest cells on hosted-fetch 5xx blips #1244) first.
Expected saving
- Latency: ~21 min off enqueue → merge for every PR that is 6th–8th in line. In the window above that was 8 of 13 PRs. Over the day, assuming about a third of 69 merges arrive in bursts, that is ~20 PRs × ~21 min ≈ 7 PR-hours/day. Merge-queue p50 should fall from ~64 toward ~45 min during bursts.
- Critical path per affected PR: −21 min (one wave).
- Cost:
- Each eviction during a burst can rebuild up to 7 entries instead of 4: ≈ +3 × 287 ≈ +860 job-min per eviction.
- At ~5–8 burst evictions/day that is +4–7k job-min/day, ~11% of it macOS (51 mac-min per full run).
- Peak concurrent macOS jobs from the queue would go from 50 (measured at 06:42 with 5 entries; 28.9 mac jobs per run) to roughly 80.
- CI perf: ci.yml e2e-macos — 23 one-minute macOS jobs per merge_group/push run (~2,300 macOS job starts/day) #1176 / Run e2e suites that share a toolchain in one leg #1234 (fewer e2e-macos legs) would offset most of that.
Coverage and risk
- No test moves; every job still runs on every merge_group run.
- Required check names are unchanged.
- Main risk: macOS pool pressure. It is shared with push-to-main runs (42/day × ~56 mac-min) and every other merge_group run. Watch macOS queue wait on the CI performance dashboard after the change.
- Second risk: more cancelled rebuild minutes while the eviction rate is still ~20–30%.
Effort
S (one ruleset field, reversible in seconds).
ROI
About 7: (≈21 critical-path min − ≈7 weighted for +5k job-min) × confidence 0.5 ÷ effort 1. Same scale as the dashboard.
Activity
mikolalysenko commentedon Oct 9, 2026
[agent] Triaged p3. This is a merge-queue ruleset change (
max_entries_to_build), which agents may not apply, so it needs a maintainer decision. Labeledagent:needs-human.Generated by Claude Code
mikolalysenko commentedon Oct 9, 2026
More evidence from the CI janitor, 2026-10-09 18:38Z: runner capacity is starving the merge queue.
pull_requestruns on current heads of 80 open PRs. 28 more are Copilotdynamicruns.CIruns created at 18:14Z and 18:20Z (pr-1284, 1286, 1288, 1247, 1290, 1274) were all stillqueuedat 18:38Z, 18 to 24 minutes after creation, before any of their test jobs started.CIrun for 9ab72d4 (run 37970501466, created 18:02Z) was stillqueued36 minutes later.Merge queue janitorsweep for the 18:02Z group itself waited for a runner until 18:17Z.I cancelled only clearly wasted runs: 4 on superseded PR SHAs and 5 duplicate runs on the same SHA. That is negligible next to the backlog. This is a capacity problem rather than a reliability one. Options for the owner: merge_group priority over PR runs (for example, a separate runner group or larger runners for
merge_group), or limiting PR pushes per agent. #1362 (Depot Linux runners) is the open PR in this direction.Generated by Claude Code
mikolalysenko commentedon Oct 9, 2026
CI janitor evidence, 2026-10-09 ~19:40 UTC:
agent/fix-vendored-reresolved-version-drift) was created 18:23, so it has waited about 75 min.I cancelled 3 runs to relieve the backlog: 2 on a superseded PR head and 1 on a draft PR.
Generated by Claude Code
mikolalysenko commentedon Oct 9, 2026
CI profiler, 2026-10-09 20:16 UTC.
Settings changed since this issue was filed. Ruleset 24668460 now has
max_entries_to_build8 (was 5) andcheck_response_timeout_minutes90 (was 120).max_entries_to_mergeis still 5. The new values can't be judged on today's data:ubuntu-latestrunners, not test time.ubuntu-22.04jobs in the same runs waited under 1.5 min.ubuntu-latestrunner whileubuntu-22.04starts in <1 min (merge-queue critical path, backlog hours) #1372 (ci-okwaits 9–18 min for a runner, S fix) and CI perf: PR CI — 23% of full PR runs re-test unchanged diffs after a merge-main push (~20–30k Linux job-min/day, feeds the ubuntu-latest backlog) #1373 (merge-main pushes drive 23% of full PR runs). Depot runners (Run Linux CI jobs on Depot runners #1362) would remove the backlog itself.Building 8 entries at once adds about 3 × 310 Linux job-min to the same backlog in a burst. Worth re-checking once #1362 or #1373 lands.
Generated by Claude Code
mikolalysenko commentedon Oct 11, 2026
CI profiler, 2026-10-11 12:17 UTC. Window: the last 24h.
Settings now: ruleset 24668460 reads
max_entries_to_build5. It was 8 at the last profile, so it has been set back.max_entries_to_mergeis 5,min_entries_to_merge_wait_minutes5, the timeout 90 min, grouping ALLGREEN.What changed underneath: since #1362 (Depot Linux) and #1375 (lean gate) merged, a merge_group
CIrun costs 29 Linux + 7.5 Windows + 0 macOS job-min. It cost 312 / 69 / 60 before. It runs created →ci-okin p50 9.6 / p90 9.95 min (n=30). Queue wait is p50/p90 0.02/0.02 min on Depot (n=2,814 jobs) and 0.03/0.03 min on Windows. The only hosted job per group is onee2e-build-windows. Building more entries at once no longer competes for a scarce pool.What 5 still costs:
clippyfailure on Restore NuGet contentHash, not catalog packageHash (#624) #1343's group, evicted in 1.4 min by fail-fast. The re-queue merged in 10.7 min.Suggestion for a human: with ~37 job-min per group and no queue wait,
max_entries_to_build10 (or more) costs about 37 extra job-min per extra entry in a burst. Bursts of 8+ entries would then merge in one ~10-min wave instead of two. The Windows job in each group is the only hosted runner, and #1385 would cut its time.Generated by Claude Code
mikolalysenko commentedon Oct 12, 2026
CI profiler, 2026-10-12 00:16 UTC. Window: the last 24h.
Settings now: unchanged since the last comment.
max_entries_to_build5,max_entries_to_merge5,min_entries_to_merge_wait_minutes5, ALLGREEN, timeout 90.This window:
max_entries_to_build. All 5 merged in 7.6–8.7 min. The other bursts were 3 entries (22:47–22:54, 23:48–23:49).ci-ok: p50 7.3 min after CI: type-check Windows in the queue, in parallel (#1385) #1386 (n=16).What this means for the decision: no burst above 5 in 48h, so a second build round has not happened since 10-11 17:31. If one does, an entry past the 5th now waits about one extra CI run, ~7.3 min (it was ~9.7 before #1386). The case for raising
max_entries_to_buildis weaker than when this was filed, though raising it is still free on Depot runners (Linux queue wait p90 0.02 min, n=2,075 jobs).Generated by Claude Code
mikolalysenko commentedon Oct 13, 2026
CI profiler, 2026-10-13 00:16 UTC. Window: the last 24h (2026-10-12 00:16 → 2026-10-13 00:16).
Settings now: unchanged since the last comment (read 00:20).
max_entries_to_build5,max_entries_to_merge5,min_entries_to_merge_wait_minutes5, ALLGREEN, timeout 90.The 15:44 burst is the only one in the window that hit the cap:
CIruns were created in waves: 15:44–15:45 (5), 15:52–15:53 (4), 16:01–16:02 (6), 16:10–16:11 (4).coverageflake (38273391986, fixed by Fix env race flake in cache_env scrub self-tests #1418). That flake also cancelled 3 runs.What this means for the setting: a merge_group
CIrun takes p50 8.15 / p90 9.2 min from creation toci-ok(n=36). Linux queue wait on Depot is p90 0.02 min, so runner capacity is not the limit. Raisingmax_entries_to_buildto 8–10 would have cut ~8 min from the 4 burst entries past the 5th. That is about 32 entry-minutes in one burst per day, and nothing in the other 31 merges. The case is weaker than when this issue was filed: bursts of more than 5 now happen about once a day, not continuously. Leaving this open for a human decision.Generated by Claude Code