-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Limit max pool size for parallel execution via config param #3044
Limit max pool size for parallel execution via config param #3044
Conversation
e8c4b30
to
6474b71
Compare
@marcphilipp To update the changelog I'd need to know which milestone would go into. |
I just created 5.10 M1. So feel free to use that. If it ends up landing in a different milestone, we'll move the change log entry accordingly. |
Note, however, that there is currently no file for the 5.10 M1 release notes. So, you'll need to follow the instructions in If that seems too cumbersome, a core committer can create the new file for you. |
6474b71
to
c977a28
Compare
JUnit Jupiter (and The JUnit Platform) now support limiting the maximum number of concurrently executing tests via the `junit.jupiter.execution.parallel.config.fixed.max-pool-size` property. With Java 9+ the `ForkJoinPool` used by JUnit can be configured with a maximum pool size. While the number of concurrently executing tests may exceed the configured parallelism when tests become blocked, it will not exceed the maximum pool size. With the following configuration: ```properties junit.jupiter.execution.parallel.enabled=true junit.jupiter.execution.parallel.config.strategy=fixed junit.jupiter.execution.parallel.mode.default=concurrent junit.jupiter.execution.parallel.config.fixed.parallelism=2 ``` This example will report between 2-5 tests running concurrently. ```java class ExampleTest { private static final AtomicInteger running = new AtomicInteger(); @beforeeach void increment() { System.out.println("Running " + running.incrementAndGet()); } @AfterEach void decrement() { running.decrementAndGet(); } static IntStream numbers() { return IntStream.range(0, 1000); } @ParameterizedTest @MethodSource("numbers") void test(int i) throws ExecutionException, InterruptedException { Runnable sleep = () -> { try { Thread.sleep(600); } catch (InterruptedException e) { throw new RuntimeException(e); } }; ForkJoinPool.commonPool().submit(sleep).get(); } } ``` By also configuring the `max-pool-size` we can ensure the concurrently executing test does not exceed the configured 2. ```properties junit.jupiter.execution.parallel.config.fixed.max-pool-size=2 ``` Additionally, because the `ForkJoinPool` will by default reject tasks that would exceed the maximum pool size the `junit.jupiter.execution.parallel.config.fixed.saturate` property has been added and will default to `true`. There appears to be no reason to ever set this `false` but it is there should someone depend on the old behaviour. These changes were intentionally not made to the `dynamic` strategy to limit the scope of this pull request. While I can reasonably predict what behaviour users of the `fixed` strategy might expect, I can not say the same about the `dynamic` strategy. Fixes: junit-team#3026 Fixes: junit-team#2545 Fixes: junit-team#1858
c977a28
to
dccc0c7
Compare
Thanks for implementing this! :) |
16a3926
to
d35e44c
Compare
For #2545: While the proposed solution involves a If more complicated solutions are needed I expect people will open a new issue to describe their exact problem in more detail. For #1858: The root cause was explained in #1858 (comment). When a test puts its executing thread to sleep, JUnit will start another test to keep up the desired parallism. However as explained in #1858 (comment) when using Selenium threads are commonly put to sleep and so it is desirable to limit the maximum pool size to limit the maximum number of web drivers created. This wasn't possible without saturating the pool. This too was fixed by #2792 and can be achieved through a custom parallel strategy. This PR simplifies the process and should for this specific use case remove the need for more complicated solutions. For #3026: Essentially this issues requests a configuration parameter to limit the maximum pool size and allow the pool to be saturated. Removing the need to create a custom class for this very common scenario, |
|
Thanks for the heads-up! I didn't see that specific problem explicitly mentioned in the issues before so I left it out of scope. I reckon the current PR can still be salvaged by fixing the wording. Limiting the max poolsize via a property is still useful. Replacing the Fork Join Pool might be a bit more involved. 😅 |
@mpkorstanje Do you want me to create a special test and open an issue for that particular problem? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good except for a few minor documentation things.
junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/Constants.java
Outdated
Show resolved
Hide resolved
...unit/platform/engine/support/hierarchical/DefaultParallelExecutionConfigurationStrategy.java
Outdated
Show resolved
Hide resolved
...unit/platform/engine/support/hierarchical/DefaultParallelExecutionConfigurationStrategy.java
Outdated
Show resolved
Hide resolved
@OPeyrusse yes, please do. I can't promise or commit to solving it. But perhaps someone can. |
Co-authored-by: Marc Philipp <[email protected]>
I think this is what @OPeyrusse had in mind. The code below will report between 2-6 active tests as the I've updated the documentation to say concurrent "threads" instead of "tests". class ExampleTest {
private static final Runnable sleep = () -> {
try {
Thread.sleep(600);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
};
private static final AtomicInteger running = new AtomicInteger();
@BeforeEach
void increment() {
System.out.println("Running " + running.incrementAndGet());
}
@AfterEach
void decrement() {
running.decrementAndGet();
}
static IntStream numbers() {
return IntStream.range(0, 1000);
}
@ParameterizedTest
@MethodSource("numbers")
void test(int i) {
ForkJoinPool.commonPool()
.submit(sleep)
.join();
}
@ParameterizedTest
@MethodSource("numbers")
void test2(int i) {
ForkJoinPool.commonPool()
.submit(sleep)
.join();
}
} |
@marcphilipp good to go. |
Changes applied! For fixing small mistakes and typos please do feel free to push directly to my branch. |
JUnit Jupiter (and The JUnit Platform) now support limiting the maximum number of concurrently executing tests via the `junit.jupiter.execution.parallel.config.fixed.max-pool-size` configuration parameter. With Java 9+ the `ForkJoinPool` used by JUnit can be configured with a maximum pool size. While the number of concurrently executing tests may exceed the configured parallelism when tests become blocked, it will not exceed the maximum pool size. Additionally, because the `ForkJoinPool` will by default reject tasks that would exceed the maximum pool size the `junit.jupiter.execution.parallel.config.fixed.saturate` property has been added and will default to `true`. There appears to be no reason to ever set this `false` but it is there should someone depend on the old behavior. These changes were intentionally not made to the `dynamic` strategy to limit the scope of this pull request. While I can reasonably predict what behavior users of the `fixed` strategy might expect, I can not say the same about the `dynamic` strategy. Fixes #3026. Fixes #2545. Fixes #1858.
With JUnit 5.9.2 we pull in junit-team/junit5#3044 which makes it possible to limit the maximum number of threads used while executing in parallel. Closes: #2677
With JUnit 5.9.2 we pull in junit-team/junit5#3044 which makes it possible to limit the maximum number of threads used while executing in parallel. Closes: #2677
With JUnit 5.9.2 we pull in junit-team/junit5#3044 which makes it possible to limit the maximum number of threads used while executing in parallel. Closes: #2677
This is a followup of junit-team#3044 for the `dynamic` strategy. Fixes: junit-team#3205
This is a followup of junit-team#3044 for the `dynamic` strategy. Fixes: junit-team#3205
Overview
With Java 9+ the
ForkJoinPool
used by JUnit can be configured with a maximum pool size via thejunit.jupiter.execution.parallel.config.fixed.max-pool-size
property.While the number of concurrently executing tests may exceed the configured parallelism when tests become blocked, it will not exceed the maximum pool size in these circumstances.
With the following configuration:
This example will report between 2-5 tests running concurrently.
By also configuring the
max-pool-size
we can ensure the concurrently executing test does not exceed the configured 2.junit.jupiter.execution.parallel.config.fixed.max-pool-size=2
Additionally, because the
ForkJoinPool
will by default reject tasks that would exceed the maximum pool size thejunit.jupiter.execution.parallel.config.fixed.saturate
property has been added and will default totrue
. There appears to be no reason to ever set thisfalse
but it is there should someone depend on the old behavior.These changes were intentionally not made to the
dynamic
strategy to limit the scope of this pull request. While I can reasonably predict what behaviour users of thefixed
strategy might expect, I can not say the same about thedynamic
strategy.Fixes: #2545
Fixes: #1858
Fixes: #3026
This PR replaces #3027.
I hereby agree to the terms of the JUnit Contributor License Agreement.
Definition of Done
@API
annotations