Consolidate test categories and enable parallel executions - #5783
Open
johnsimons wants to merge 5 commits into
Open
Consolidate test categories and enable parallel executions#5783johnsimons wants to merge 5 commits into
johnsimons wants to merge 5 commits into
Conversation
Groups test projects that share infrastructure (like SQL Server or RabbitMQ) into consolidated categories to reduce container provisioning and compilation overhead. Updates the test runner to support parallel execution of assemblies on a single runner to maintain performance, including output buffering to prevent interleaved logs.
Assigns unique ports to test runs via environment variables when parallel execution is enabled. This avoids collisions where multiple processes probe the same available port simultaneously before binding. Includes an update to the process exit logic to use a timeout, preventing potential hangs caused by inherited handles in child processes.
Adds a detailed research and recommendation document for optimizing CI runner usage through job consolidation and step parallelism. Updates event source creation logic to handle race conditions that occur when multiple test assemblies attempt to create machine-wide resources concurrently on the same runner.
Switches from capturing loop output to using an explicit list to ensure diagnostic messages (Write-Output) do not pollute the collection of test runs. This prevents invalid "dotnet test" executions that would occur if strings were accidentally included in the runs array.
Removes the RavenDB port information from the "Starting" log message to ensure a consistent output format for all test executions.
johnsimons
marked this pull request as ready for review
August 16, 2026 22:27
rbev
approved these changes
Aug 17, 2026
Contributor
There was a problem hiding this comment.
Should this plan be converted into as built documentation or removed?
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.
I decided to tackle CI timings again, and this time I went down the path of doing the opposite of what I did last time.
The last round split test categories apart so jobs could run side by side, which bought wall clock by spending runners. We kept adding categories after that, and a run had grown to 52 jobs against our 60 job org wide cap. So a single run was using 87% of the budget for every Particular repo, and any second run in flight sat in the queue for minutes.
I started out looking at parallelising more steps inside the jobs, but the step timings killed that idea. Where a job provisions infrastructure the backgrounded build is already completely hidden behind it, and where it does not there is nothing to overlap with. The win was in the other direction: the critical path was 870s while 34 of 41 jobs finished under 420s, and that slack is what you spend to get runners back.
What I changed
Set
concurrencyon the workflow. We were never cancelling superseded runs. Over the last 120 runs, zero were cancelled and 23 pairs overlapped, the worst holding a full run for 27 minutes. This was the biggest single cause of the queueing and it costs nothing. It cancels on master too, deliberately. Releases are unaffected, they run fromrelease.ymlon a tag and this workflow never triggers on tags.Merged the categories that share infrastructure, 20 down to 11. The merge is declared in the projects, by sharing a
<TestCategory>value, not in the workflow. I tried it in the matrix first and it was worse: you end up string matching category names in YAML and duplicating the mapping across the csproj files. Doing it in the project meantselect-test-projects.ps1needed no change andServiceControl_TESTS_FILTERkept working.RavenRabbitMQSqlServerPostgreSqlOne database server per category instead of two. Both provisioning actions hardcode their host port, so a job can only invoke each once, and it turns out it only needs to. The persistence and acceptance suites create a database per test and the transport suite uses randomly suffixed queue tables, so they share a server fine. We also stop paying for the SQL Server full text install twice.
Added
-MaxParalleltorun-tests.ps1so a multi-project category costs the slowest assembly rather than the sum. Defaults to 1, so anything single-project behaves as before.Results
I expected to trade wall clock for runners and instead got both. Merging the SQL Server categories turned out faster merged than the old critical path was split:
Windows-SqlServerruns all three suites in 723s on one runner, whereWindows-PrimarySqlServerAcceptancealone took 870s across three.Before merging
The required status checks need updating, otherwise this cannot go green.
Remove, each in
Windows-andLinux-form:DefaultAudit,PrimaryRavenAcceptance,PrimaryRavenPersistence,PrimarySqlServerAcceptance,PrimaryPostgreSqlAcceptance,SqlServerPersistence,PostgreSqlPersistence,RabbitMQClassicConventional,RabbitMQClassicDirect,RabbitMQQuorumConventional,RabbitMQQuorumDirect.Add:
Windows-Raven,Linux-Raven,Windows-RabbitMQ,Linux-RabbitMQ.SqlServerandPostgreSqlstay, they just cover more now.