Split the legacy test stage into four buckets - #9802
Open
Groenbech96 wants to merge 1 commit into
Open
Conversation
Buckets are separate jobs on separate runners with separate containers, so they run fully in parallel - run 30354787707 used 44 distinct runners with Bucket1 and Bucket2 starting in the same minute. Splitting the work across more buckets therefore adds real, contention-free capacity, unlike raising the tenant count inside one container. Measured on run 30354787707 (W1), Bucket1 carries 388.4 min of test work against Bucket2's 313.1, so the stage is bound by Bucket1. The constraint that shapes the split: only LegacyTestsBucket1 containers get additionalDemoDataTypes ["Standard","Evaluation"], so an app cannot move between the two classes without changing the data it tests against. Keeping every app in its current class: split Bucket2 in two 388.4 / 156.5 / 156.5 -> critical 388.4 (no gain) split Bucket1 in two 194.4 / 194.0 / 313.1 -> critical 313.1 (-19%) split both (this PR) 194.4 / 194.0 / 156.5 / 156.5 -> critical 194.4 (-50%) The intuitive "add a third bucket" is worthless unless it splits Bucket1, and the unconstrained ideal 3-way (233.8 min) is unreachable across the demo-data boundary - which is why this goes to four rather than three. Bucket3 is a sibling of Bucket1 and inherits its additionalDemoDataTypes; Bucket4 is a sibling of Bucket2. No app changes demo-data class, and no app changes the dataset it runs against. Assignment is LPT over each class using measured per-app times from run 30354787707, and each list is ordered longest-first for the FIFO dispatch loop. No code changes were needed: Get-AppNamesForBucket already resolves "LegacyTests-Bucket$N" generically and the Uncategorized path discovers every LegacyTests-* key. Adds six Pester tests over the bucket configuration, because the failure modes here are silent: an app listed twice runs its tests twice, and an app listed nowhere falls through to the Uncategorized build mode with a different testType and company rather than erroring. Both new guards were negative-tested by injecting a duplicate and a non-contiguous bucket. build/scripts Pester suite: 124/124 pass. Note: with four buckets each bucket becomes app-bound rather than tenant-bound (work/6 is 26-32 min against a largest app of 45.6-51.7), so numberOfTenantsForTesting should be re-tuned downward in a follow-up, and splitting Tests-Workflow / AlCosting becomes worthwhile for the first time. Left out here to keep this change to a single variable. Co-authored-by: Copilot <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Buckets are separate jobs on separate runners with separate containers, so they run fully in parallel — run
30354787707used 44 distinct runners, with Bucket1 and Bucket2 starting in the same minute. Adding a bucket therefore buys real, contention-free capacity, which raising the tenant count inside one container does not.That distinction matters because the legacy stage has hit its contention ceiling. Measured in
30354787707, both buckets are already tenant-bound, and #9736 showed that adding parallelism inside a container now costs almost as much in per-test slowdown as it gains: splittingTests-ERMraised Bucket1's concurrency and made every other app in that bucket 10–19% slower, inflating bucket work +27% for a net −5%.The constraint that shapes the split
Only
LegacyTestsBucket1containers getadditionalDemoDataTypes: ["Standard","Evaluation"]. An app cannot move between the two classes without changing the dataset it tests against, so the classes cannot be freely rebalanced.Keeping every app in its current class, using measured per-app times from run
30354787707(W1):Two non-obvious results:
What
Bucket3is a sibling of Bucket1 and inherits itsadditionalDemoDataTypes;Bucket4is a sibling ofBucket2. No app changes demo-data class, so no app changes the data it runs against.Get-AppNamesForBucketalready resolves"LegacyTests-Bucket$N"generically, and the Uncategorized path discovers everyLegacyTests-*key.Tests-Workflow51.7Tests-SCM50.9AlCosting45.6Tests-SCM-Warehouse46.0Cost
Legacy jobs go from 44 → 88 (22 countries × 4). Roughly +87 runner-hours per build against the 129.2 measured today, because ~97 min of container setup is paid per job. This is the trade to weigh: it is the only lever that adds real capacity, and the only one that costs materially more compute.
Tests
Adds six Pester tests over the bucket configuration. These failure modes are silent, which is why they are worth guarding:
testTypeandcompanyName.Both new guards were negative-tested by injecting a duplicate app and a non-contiguous bucket number, and both failed as intended.
Get-AppNamesForBucketpreviously had no test coverage at all.build/scriptsPester suite: 124/124 pass.Follow-ups deliberately left out
Kept to a single variable so the next run measures the bucket change cleanly:
numberOfTenantsForTestingdownward. With four buckets each bucket becomes app-bound rather than tenant-bound —work/6is 26–32 min against a largest app of 45.6–51.7 — so tenants 5 and 6 are provably idle. The model puts 4–5 tenants at the same floor with materially less contention.Tests-Workflow(51.7 min) andAlCosting(45.6 min). In the current 2-bucket layout these have 30 and 38 min of slack and splitting them is worth nothing. Once buckets are this small they become the binding constraint, and splitting them pays for the first time.AlCostingis a single codeunit, so it needs a source-level split.Co-authored-by: Copilot [email protected]