Skip to content
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

Getting configMapping with ConfigProvider or Arc in a forkjoinpool causes QuarkusConfigFactory not a subtype exception #24896

Closed
manofthepeace opened this issue Apr 12, 2022 · 7 comments
Labels
area/arc Issue related to ARC (dependency injection) area/config kind/bug Something isn't working

Comments

@manofthepeace
Copy link
Contributor

Describe the bug

I have closed #24276 since it was getting clogged with only stacktraces and no traction. Sorry for the noise, I am reopening here with a proper reproducer in the hope some light can be shed on that.

When using Arc.container, or ConfigProvider, to fetch a configMapping in a non cdi bean, causes the following exception;Caused by: java.util.ServiceConfigurationError: io.smallrye.config.SmallRyeConfigFactory: io.quarkus.runtime.configuration.QuarkusConfigFactory not a subtype

Expected behavior

It should work and not cause any sort of exception

Actual behavior

Exception happens

How to Reproduce?

Reproducer; https://github.com/manofthepeace/quarkus-config-forkjoinpool

Steps to reproduce;
1- mvn quarkus:dev
2- wait 5 sec (a scheduled method will run)
3- In Entity.java the Arc.container() can be uncommented exhibiting similar behaviour.

Output of uname -a or ver

Darwin Kernel Version 20.6.0

Output of java -version

OpenJDK Runtime Environment Temurin-17.0.2+8 (build 17.0.2+8)

GraalVM version (if different from Java)

No response

Quarkus version or git rev

2.7.4

Build tool (ie. output of mvnw --version or gradlew --version)

maven 3.8.4

Additional information

No response

@manofthepeace manofthepeace added the kind/bug Something isn't working label Apr 12, 2022
@quarkus-bot quarkus-bot bot added the area/arc Issue related to ARC (dependency injection) label Apr 12, 2022
@quarkus-bot
Copy link

quarkus-bot bot commented Apr 12, 2022

/cc @manovotn, @mkouba

@mkouba
Copy link
Contributor

mkouba commented Apr 13, 2022

It seems that the ServiceConfigurationError is only thrown in the dev mode. Am I right? I get a different error in the prod mode: java.util.NoSuchElementException: SRCFG00027: Could not find a mapping for org.acme.PotatoConfig.

I think that you'll need to capture the thread context class loader in the scheduled method (Thread.current().getContextClassLoader()) and use this CL in the task submitted to the ForkJoinPool (Thread.current().setContextClassLoader()).

CC @radcortez

@manofthepeace
Copy link
Contributor Author

Thanks for your reply. In my real world app, I am using stream().parallelStream().forEach(this::doSomething); which underneats uses a forkjoinpool. What surprises me, is that it does not fail all the time, my scheduled task, which is every 3 mins, can work for like 12 to 22 mins before I start seeing the error. For now I have only seen it in dev mode, but it does worry me for when I run in prod.

In the case of the parallelStream, I am no sure how to use Thread.current().getContextClassLoader()

@radcortez
Copy link
Member

This is related with:

#20178
#20067

It should work. That exception means that a Config instance could not be found in the current ClassLoader, and a new one had to be created. Because the classes are not on the same ClassLoader you get the exception.

My recommendation is to just retrieve the configuration value before and just pass down the value, or you need to make sure to get the correct ClassLoader as stated by @mkouba

@radcortez
Copy link
Member

Just to add that using ForkJoinPool forkJoinPool = new ForkJoinPool(2); will default to the System ClassLoader as the ThreadContext ClassLoader. Because Config (or Arc) are not in ths ClassLoader you experience the reported issues.

My recommendation is to specify the QuarkusForkJoinWorkerThreadFactory like new ForkJoinPool(2, new QuarkusForkJoinWorkerThreadFactory(), null, false); or just use the common pool ForkJoinPool.commonPool(). Both will work as expected.

@andreas-trvlk
Copy link

Hi @manofthepeace. I encountered similar issue when running stream().parallelStream().forEach(this::doSomething);. Have you found any solution or workaround? The suggested solutions are not confusing. Not sure how to apply that ClassLoader trick into stream().parallelStream().forEach(this::doSomething);.

@manofthepeace
Copy link
Contributor Author

@andreas-trvlk The easiest is to use quarkus' own ManagedExecutor.

    @Inject
    @ManagedExecutorConfig(maxAsync = 150)
    ManagedExecutor executor;

then you can use something like this;

stream.foreach(s->{
executor.runAsync(()->doSomething())
});

Please note the @ManagedExecutorConfig(maxAsync = 150). I had problem when not having a limit on the managedExecutor, by default it has 200 threads, and then not limiting it looks like the stream processing could hang other quarkus features that may use it. I may be wrong here, but It definitely solve the issue discussed here for me; #27007

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/arc Issue related to ARC (dependency injection) area/config kind/bug Something isn't working
Projects
None yet
Development

No branches or pull requests

5 participants