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

Unexpected beans added to the index and affecting restarting the application #29575

Closed
pedroigor opened this issue Nov 30, 2022 · 8 comments · Fixed by #29641
Closed

Unexpected beans added to the index and affecting restarting the application #29575

pedroigor opened this issue Nov 30, 2022 · 8 comments · Fixed by #29641
Labels
area/arc Issue related to ARC (dependency injection) area/devmode kind/bug Something isn't working
Milestone

Comments

@pedroigor
Copy link
Contributor

pedroigor commented Nov 30, 2022

Describe the bug

I did not manage to come up with a reproducer using a regular Quarkus application. But the issue happens if you try out this branch https://github.com/pedroigor/keycloak/tree/tmp-reactive.

That branch is about switching from Resteasy Classic to Reactive in Keycloak. The issue does not happen if using Resteasy Classic and I'm not sure what is the relation, if any.

Basically, when reloading the application in dev mode or when running tests using the QuarkusMainTestExtension, reloading the application fails with this error:

org.junit.jupiter.api.extension.ParameterResolutionException: Failed to resolve parameter [io.quarkus.test.junit.main.LaunchResult arg0] in method [void org.keycloak.it.cli.StartCommandTest.testHttpEnabled(io.quarkus.test.junit.main.LaunchResult)]: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
    [error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: Found 8 deployment problems: 
[1] Ambiguous dependencies for type javax.transaction.TransactionManager and qualifiers [@Default]
    - java member: io.quarkus.agroal.runtime.DataSources():transactionManager
    - declared on CLASS bean [types=[io.quarkus.agroal.runtime.DataSources, java.lang.Object], qualifiers=[@Default, @Any], target=io.quarkus.agroal.runtime.DataSources]
    - available beans:
        - CLASS bean [types=[java.io.Serializable, javax.transaction.TransactionManager, com.arjuna.ats.jta.cdi.NarayanaTransactionManager, com.arjuna.ats.jta.cdi.DelegatingTransactionManager, java.lang.Object], qualifiers=[@Default, @Any], target=com.arjuna.ats.jta.cdi.NarayanaTransactionManager]
        - CLASS bean [types=[javax.transaction.TransactionManager, java.io.Serializable, io.quarkus.narayana.jta.runtime.CDIDelegatingTransactionManager, java.lang.Object], qualifiers=[@Default, @Any], target=io.quarkus.narayana.jta.runtime.CDIDelegatingTransactionManager]

The first start of the application works fine and only CDIDelegatingTransactionManager is available to resolve TransactionManager bean types. However, reloading the application causes the
com.arjuna.ats.jta.cdi.NarayanaTransactionManager to also be recognized as a potential resolver hence failing with that error.

If we remove the com.arjuna.ats.jta.cdi.NarayanaTransactionManager at build time from our extension, the issue does not happen:

buildTimeConditionBuildItemBuildProducer.produce(new BuildTimeConditionBuildItem(index.getIndex().getClassByName(DotName.createSimple("com.arjuna.ats.jta.cdi.NarayanaTransactionManager")), false));`

Expected behavior

Being able to reload the application without introducing beans that otherwise should be excluded.

Actual behavior

Failing to reload the application as per the description.

How to Reproduce?

Output of uname -a or ver

Linux fedora 6.0.9-200.fc36.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Nov 16 17:50:45 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

Output of java -version

openjdk version "18.0.2.1" 2022-08-18 OpenJDK Runtime Environment (build 18.0.2.1+1-1) OpenJDK 64-Bit Server VM (build 18.0.2.1+1-1, mixed mode, sharing)

GraalVM version (if different from Java)

No response

Quarkus version or git rev

2.14.1.Final

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

No response

Additional information

No response

@pedroigor pedroigor added the kind/bug Something isn't working label Nov 30, 2022
@pedroigor pedroigor changed the title Unpextected beans added to the index and affecting the result of the application reload Unpextected beans added to the index and affecting the result of the application restart Nov 30, 2022
@pedroigor pedroigor changed the title Unpextected beans added to the index and affecting the result of the application restart Unpextected beans added to the index and affecting restarting the application Nov 30, 2022
@pedroigor
Copy link
Contributor Author

After talking with @stuartwdouglas, he mentioned that a possible cause is:

There is a thing called io.quarkus.deployment.index.PersistentClassIndex that stores the indexed classes between restarts to make hot reload faster
io.quarkus.arc.processor.BeanArchives#buildBeanArchiveIndex is (incorrectly) treating everything in PersistentClassIndex as a bean
But ReflectiveHeirachyBuildItem can result in additional stuff being added to PersistentClassIndex, including NarayanaTransactionManager if TransactionManager is involved anywhere (as this will index all implementors)
So on the second restart NarayanaTransactionManager is a bean

@famod famod added area/arc Issue related to ARC (dependency injection) and removed triage/needs-triage labels Nov 30, 2022
@quarkus-bot
Copy link

quarkus-bot bot commented Nov 30, 2022

/cc @manovotn, @mkouba

@geoand geoand changed the title Unpextected beans added to the index and affecting restarting the application Unexpected beans added to the index and affecting restarting the application Dec 1, 2022
@mkouba
Copy link
Contributor

mkouba commented Dec 1, 2022

So the PersistentClassIndex got introduced in this pull request as an optimization for ArC where any class (not only but mostly from JDK) computed by the io.quarkus.arc.processor.BeanArchives.IndexWrapper was kept during restarts in the dev mode. In order to become a bean a class from this PersistentClassIndex must be annotated with a bean defining annotation (e.g. scope).

A few of months later it went into the core and got reused by the io.quarkus.deployment.index.IndexWrapper.

Basically, any client of BeanArchiveIndexBuildItem.getIndex() and CombinedIndexBuildItem.getComputingIndex() can add something to the persistent class index via IndexView#getClassByName().

Now, it seems that the com.arjuna.ats.jta.cdi.NarayanaTransactionManager is indexed druing the bean discovery (but after the BeanDeployment builds the set of known classes) and after the restart it becomes a known class and since it's annotated with @ApplicationScoped it becomes a bean and thus ambiguous dependencies.

I have no idea why it's indexed - I only found that it's indexed via BeanArchiveIndexBuildItem.getIndex() - but I think that the PersistentClassIndex should only retain JDK classes (which was probably the original intent) because it's not safe to retain all computed results.

CC @stuartwdouglas @manovotn @Ladicek

@mkouba
Copy link
Contributor

mkouba commented Dec 1, 2022

By the way, the narayana-jta-5.13.1.Alpha1.jar contains the Jandex index so it should be part of the CombinedIndexBuildItem.getIndex() but it's ignored when building the bean archive because it does not contain beans.xml but a CDI portable extension and therefore is not considered an implicit CDI bean archive.

@pedroigor
Copy link
Contributor Author

@mkouba Thanks. For now, I'm excluding NarayanaTransactionManager programmatically from our extension. Once the issue is fixed I'll remove this code.

Thanks for looking at it.

Out of curiosity, why it does not happen when using resteasy classic? Is there any relation you can think of? I can re-run my tests, but if I just revert our extension to use resteasy classic, everything works fine.

@mkouba
Copy link
Contributor

mkouba commented Dec 2, 2022

Thanks. For now, I'm excluding NarayanaTransactionManager programmatically from our extension. Once the issue is fixed I'll remove this code.

Note that BuildTimeConditionBuildItem was not intended to be used to exclude a type from discovery. ExcludedTypeBuildItem is a more convenient build item for this task. Alternatively, you can use the quarkus.arc.exclude-types config property.

@mkouba
Copy link
Contributor

mkouba commented Dec 2, 2022

Out of curiosity, why it does not happen when using resteasy classic? Is there any relation you can think of? I can re-run my tests, but if I just revert our extension to use resteasy classic, everything works fine.

Stuart was right that the NarayanaTransactionManager is indexed because of a ReflectiveHierarchyBuildItem, most likely produced for the javax.transaction.TransactionManager; this includes indexing of all known implementors/subclasses. And as I mentioned in #29575 (comment) - the NarayanaTransactionManager is included in the CombinedIndexBuildItem.

mkouba added a commit to mkouba/quarkus that referenced this issue Dec 2, 2022
- this is index is mandatory and is used to discover beans
- the computing index is optional and can be used for other tasks, e.g. during type-safe resolution
- if the computing index is not present the immutable index is used
instead
- fixes quarkusio#29575
@mkouba
Copy link
Contributor

mkouba commented Dec 2, 2022

#29641 should solve the problem...

mkouba added a commit to mkouba/quarkus that referenced this issue Dec 5, 2022
- this is index is mandatory and is used to discover beans
- the computing index is optional and can be used for other tasks, e.g. during type-safe resolution
- if the computing index is not present the immutable index is used
instead
- fixes quarkusio#29575
mkouba added a commit to mkouba/quarkus that referenced this issue Dec 5, 2022
- this is index is mandatory and is used to discover beans
- the computing index is optional and can be used for other tasks, e.g. during type-safe resolution
- if the computing index is not present the immutable index is used
instead
- fixes quarkusio#29575
@gsmet gsmet closed this as completed in c2ab342 Dec 5, 2022
@quarkus-bot quarkus-bot bot added this to the 2.16 - main milestone Dec 5, 2022
@gsmet gsmet modified the milestones: 2.16 - main, 2.15.0.Final Dec 6, 2022
gsmet pushed a commit to gsmet/quarkus that referenced this issue Dec 6, 2022
- this is index is mandatory and is used to discover beans
- the computing index is optional and can be used for other tasks, e.g. during type-safe resolution
- if the computing index is not present the immutable index is used
instead
- fixes quarkusio#29575

(cherry picked from commit c2ab342)
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/devmode kind/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants