Run test files in parallel on Windows PowerShell 5.1 too - #2987
Merged
Conversation
Run.Parallel was built on ForEach-Object -Parallel, which only exists on PowerShell 7, so on Windows PowerShell 5.1 it warned and ran sequentially. 5.1 is the slowest leg in our own matrix and it is the one that sets how long a build takes, so it is the edition that needs this most. Both editions now go through Invoke-InRunspacePool, a runspace pool built on the API that 5.1 and 7 both have. One code path, so the two editions cannot drift. The worker scriptblock takes its values as named parameters instead of $using:, which is a ForEach-Object -Parallel feature, and it is handed over as text and re-parsed in the worker so nothing with runspace affinity crosses. The runspaces are in this process either way, so the values still cross as live objects. A pooled runspace starts at the process working directory rather than the caller's location, which ForEach-Object -Parallel preserves, so the worker sets it from the parent. The tests that were asserting parallel behaviour only on 7+ now run on both, so 5.1 is covered by the same assertions and not by a fallback message. Added tests for the pool itself: concurrency, throttle, parameter passing, one worker throwing without taking the rest down, and empty input. No new dependency, the implementation is in the module. 🤖
The throttle test slept 4 x 500ms through one runspace and asserted the run took at least 2000ms. Start-Sleep can come back a hair early, so the total lands just under the threshold and the test fails for a reason that has nothing to do with the pool. It did exactly that on the PS7 Windows 2022 leg. Each worker now counts itself in and out of a synchronized hashtable, so the peak number in flight is measured rather than inferred from a clock. One runspace can only ever peak at 1, which is exact, and the concurrent case asserts more than one in flight without pinning the peak to a number the scheduler decides. 🤖
It reads like a way to turn parallel off, and it is not. The files still go through the parallel machinery, one at a time in their own runspace, so the isolation stays and a breakpoint set in the calling session still does not hit inside a worker. 🤖
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.
Run.Parallelwas built onForEach-Object -Parallel, which only exists on PowerShell 7, so Windows PowerShell 5.1 warned and ran sequentially. 5.1 is the slowest leg in our matrix and it decides how long a build takes (#2985), so it is the edition that needs this most.Both editions now go through
Invoke-InRunspacePool, a pool built on the runspace API that 5.1 and 7 both have. No new dependency, about 90 lines inPester.Parallel.ps1.Three things
ForEach-Object -Paralleldid that the pool does not:$using:is its feature, not the runspace API's, so the worker takes named parameters instead. Same process either way, so the values still cross as live objects.ForEach-Object -Parallelkeeps the location and test files resolve relative paths against it, so the worker sets it from the parent.Passing the values as arguments instead of capturing them with
$using:is a tip @DarkLite1 gave in #2971. Thanks.The parallel tests no longer skip their assertions on 5.1, they run the same ones as on 7 including the console output snapshot. Added tests for the pool itself: concurrency, throttle, parameter passing, a worker throwing, empty input.
🤖