Ensure that Java's ForkJoinPool is initialized with Quarkus' ThreadPoolFactory
Closes #30120 Signed-off-by: Alexander Schwartz <aschwart@redhat.com>
This commit is contained in:
parent
20368b35b9
commit
1b821f3267
4 changed files with 27 additions and 3 deletions
3
quarkus/dist/src/main/content/bin/kc.bat
vendored
3
quarkus/dist/src/main/content/bin/kc.bat
vendored
|
@ -165,7 +165,8 @@ if "x%JAVA%" == "x" (
|
||||||
|
|
||||||
set CLASSPATH_OPTS="%DIRNAME%..\lib\quarkus-run.jar"
|
set CLASSPATH_OPTS="%DIRNAME%..\lib\quarkus-run.jar"
|
||||||
|
|
||||||
set JAVA_RUN_OPTS=%JAVA_OPTS% -Dkc.home.dir="%DIRNAME%.." -Djboss.server.config.dir="%DIRNAME%..\conf" -Dkeycloak.theme.dir="%DIRNAME%..\themes" %SERVER_OPTS% -cp %CLASSPATH_OPTS% io.quarkus.bootstrap.runner.QuarkusEntryPoint %CONFIG_ARGS%
|
rem The property 'java.util.concurrent.ForkJoinPool.common.threadFactory' is set here, as a Java Agent or enabling JMX might initialize the factory before Quarkus can set the property in JDK21+.
|
||||||
|
set JAVA_RUN_OPTS=-Djava.util.concurrent.ForkJoinPool.common.threadFactory=io.quarkus.bootstrap.forkjoin.QuarkusForkJoinWorkerThreadFactory %JAVA_OPTS% -Dkc.home.dir="%DIRNAME%.." -Djboss.server.config.dir="%DIRNAME%..\conf" -Dkeycloak.theme.dir="%DIRNAME%..\themes" %SERVER_OPTS% -cp %CLASSPATH_OPTS% io.quarkus.bootstrap.runner.QuarkusEntryPoint %CONFIG_ARGS%
|
||||||
|
|
||||||
set OPTIMIZED_OPTION=--optimized
|
set OPTIMIZED_OPTION=--optimized
|
||||||
set HELP_LONG_OPTION=--help
|
set HELP_LONG_OPTION=--help
|
||||||
|
|
3
quarkus/dist/src/main/content/bin/kc.sh
vendored
3
quarkus/dist/src/main/content/bin/kc.sh
vendored
|
@ -157,7 +157,8 @@ esceval_args() {
|
||||||
|
|
||||||
JAVA_RUN_OPTS=$(echo "$JAVA_OPTS" | xargs printf '%s\n' | esceval_args)
|
JAVA_RUN_OPTS=$(echo "$JAVA_OPTS" | xargs printf '%s\n' | esceval_args)
|
||||||
|
|
||||||
JAVA_RUN_OPTS="$JAVA_RUN_OPTS $SERVER_OPTS -cp $CLASSPATH_OPTS io.quarkus.bootstrap.runner.QuarkusEntryPoint ${CONFIG_ARGS#?}"
|
# The property 'java.util.concurrent.ForkJoinPool.common.threadFactory' is set here, as a Java Agent or enabling JMX might initialize the factory before Quarkus can set the property in JDK21+.
|
||||||
|
JAVA_RUN_OPTS="-Djava.util.concurrent.ForkJoinPool.common.threadFactory=io.quarkus.bootstrap.forkjoin.QuarkusForkJoinWorkerThreadFactory $JAVA_RUN_OPTS $SERVER_OPTS -cp $CLASSPATH_OPTS io.quarkus.bootstrap.runner.QuarkusEntryPoint ${CONFIG_ARGS#?}"
|
||||||
|
|
||||||
if [ "$PRINT_ENV" = "true" ]; then
|
if [ "$PRINT_ENV" = "true" ]; then
|
||||||
echo "Using JAVA_OPTS: $JAVA_OPTS"
|
echo "Using JAVA_OPTS: $JAVA_OPTS"
|
||||||
|
|
|
@ -29,6 +29,7 @@ import static org.keycloak.quarkus.runtime.cli.command.Start.isDevProfileNotAllo
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ForkJoinPool;
|
||||||
|
|
||||||
import jakarta.enterprise.context.ApplicationScoped;
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
import org.keycloak.common.profile.ProfileException;
|
import org.keycloak.common.profile.ProfileException;
|
||||||
|
@ -56,6 +57,8 @@ import io.quarkus.runtime.annotations.QuarkusMain;
|
||||||
public class KeycloakMain implements QuarkusApplication {
|
public class KeycloakMain implements QuarkusApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
ensureForkJoinPoolThreadFactoryHasBeenSetToQuarkus();
|
||||||
|
|
||||||
System.setProperty("kc.version", Version.VERSION);
|
System.setProperty("kc.version", Version.VERSION);
|
||||||
List<String> cliArgs = null;
|
List<String> cliArgs = null;
|
||||||
try {
|
try {
|
||||||
|
@ -96,6 +99,25 @@ public class KeycloakMain implements QuarkusApplication {
|
||||||
parseAndRun(cliArgs);
|
parseAndRun(cliArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that the property for the ForkJoinPool factory set by Quarkus matches the actual factory.
|
||||||
|
* If this is not the case, the classloader for those threads is not set correctly, and for example loading configurations
|
||||||
|
* via SmallRye is unreliable. This can happen if a Java Agent or JMX initializes the ForkJoinPool before Java's main method is run.
|
||||||
|
*/
|
||||||
|
private static void ensureForkJoinPoolThreadFactoryHasBeenSetToQuarkus() {
|
||||||
|
// At this point, the settings from the CLI are no longer visible as they have been overwritten in the QuarkusEntryPoint.
|
||||||
|
// Therefore, the only thing we can do is to check if the thread pool class name is the same as in the configuration.
|
||||||
|
final String FORK_JOIN_POOL_COMMON_THREAD_FACTORY = "java.util.concurrent.ForkJoinPool.common.threadFactory";
|
||||||
|
String sf = System.getProperty(FORK_JOIN_POOL_COMMON_THREAD_FACTORY);
|
||||||
|
//noinspection resource
|
||||||
|
if (!ForkJoinPool.commonPool().getFactory().getClass().getName().equals(sf)) {
|
||||||
|
Logger.getLogger(KeycloakMain.class).errorf("The ForkJoinPool has been initialized with the wrong thread factory. The property '%s' should be set on the Java CLI to ensure Java's ForkJoinPool will always be initialized with '%s' even if there are Java agents which might initialize logging or other capabilities earlier than the main method.",
|
||||||
|
FORK_JOIN_POOL_COMMON_THREAD_FACTORY,
|
||||||
|
sf);
|
||||||
|
throw new RuntimeException("The ForkJoinPool has been initialized with the wrong thread factory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void handleUsageError(String message) {
|
private static void handleUsageError(String message) {
|
||||||
handleUsageError(message, null);
|
handleUsageError(message, null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,7 @@
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<configuration>
|
<configuration>
|
||||||
<argLine>-Djdk.net.hosts.file=${project.build.testOutputDirectory}/hosts_file -XX:+ExitOnOutOfMemoryError -XX:+HeapDumpOnOutOfMemoryError --add-opens=java.base/java.security=ALL-UNNAMED</argLine>
|
<argLine>-Djdk.net.hosts.file=${project.build.testOutputDirectory}/hosts_file -XX:+ExitOnOutOfMemoryError -XX:+HeapDumpOnOutOfMemoryError --add-opens=java.base/java.security=ALL-UNNAMED -Djava.util.concurrent.ForkJoinPool.common.threadFactory=io.quarkus.bootstrap.forkjoin.QuarkusForkJoinWorkerThreadFactory</argLine>
|
||||||
<systemPropertyVariables>
|
<systemPropertyVariables>
|
||||||
<kc.quarkus.tests.dist>${kc.quarkus.tests.dist}</kc.quarkus.tests.dist>
|
<kc.quarkus.tests.dist>${kc.quarkus.tests.dist}</kc.quarkus.tests.dist>
|
||||||
</systemPropertyVariables>
|
</systemPropertyVariables>
|
||||||
|
|
Loading…
Reference in a new issue