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

Hibernate Reactive can't be used when agroal extension is present #33380

Closed
tomas1885 opened this issue May 15, 2023 · 4 comments · Fixed by #33790
Closed

Hibernate Reactive can't be used when agroal extension is present #33380

tomas1885 opened this issue May 15, 2023 · 4 comments · Fixed by #33790
Labels
area/agroal area/hibernate-reactive Hibernate Reactive area/persistence OBSOLETE, DO NOT USE kind/bug Something isn't working
Milestone

Comments

@tomas1885
Copy link
Contributor

Describe the bug

When Agroal extension is added as a depedency along side a reactive sql client, hibernate reactive can't be used.
As described in other issues, this prevents using reactive datasource along side flyway, liquibase, quartz etc. as they require a blocking datasource.
Once the agroal extension is present it automatically adds a jdbcdatasource that gets detected by the hibernate orm extension which is preset as a transient dependency for hibernate reactive.
This seems to actually boil down to the defineTypeOfImpliedPU method in the HiberanateOrmProcessor.
Other issues mentions that this can be fixed when Quarkus migrates to hibernate 6 and hibernate reactive 2.0, but it really seems like a "naive" assumption in the hibernate orm quarkus extension, which can be (hopefully) easy to fix by either allowing the user to disable blocking hibernate persistence unit, or by detecting the persistent unit associated datasource flavor (reactive or blocking).

#10716 (comment)
#13425

Expected behavior

When using Hibernate reactive with a reactive datasource configured, adding the agroal extension and configuring a blocking datasource, without associating it to hibernate persistence unit won't affect hibernate blocking/reactive mode.

Actual behavior

Configuring Hibernate Reactive with a reactive datasource as the datasource, while also adding another blocking datasource using agroal, causes all sort of exceptions due to the generation of ImpliedBlockingPersistenceUnitTypeBuildItem.

How to Reproduce?

No response

Output of uname -a or ver

No response

Output of java -version

17

GraalVM version (if different from Java)

No response

Quarkus version or git rev

3.0.3.Final

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

Gradle 8.0.2

Additional information

No response

@tomas1885 tomas1885 added the kind/bug Something isn't working label May 15, 2023
@quarkus-bot quarkus-bot bot added area/agroal area/hibernate-reactive Hibernate Reactive area/persistence OBSOLETE, DO NOT USE labels May 15, 2023
@quarkus-bot
Copy link

quarkus-bot bot commented May 15, 2023

/cc @DavideD (hibernate-reactive), @Sanne (agroal,hibernate-reactive), @barreiro (agroal), @gavinking (hibernate-reactive), @yrodiere (agroal)

@tomas1885
Copy link
Contributor Author

tomas1885 commented May 19, 2023

How changing the implementation of defineTypeOfImpliedPU to something like that:

   @BuildStep
    public ImpliedBlockingPersistenceUnitTypeBuildItem defineTypeOfImpliedPU(
            HibernateOrmConfig config,
            List<JdbcDataSourceBuildItem> jdbcDataSourcesBuildItem, //This is from Agroal SPI: safe to use even for Hibernate Reactive
            List<PersistenceXmlDescriptorBuildItem> actualXmlDescriptors,
            Capabilities capabilities) {
        var jdbcDataSourceEnabled = true;
        if (config.persistenceUnits.isEmpty()) {
            var defaultDataSourceJdbcPropertyKey = config.defaultPersistenceUnit.datasource
                    .map(name -> DataSourceUtil.dataSourcePropertyKeys(name, "jdbc"))
                    .orElse(List.of("quarkus.datasource.jdbc"));
            jdbcDataSourceEnabled = defaultDataSourceJdbcPropertyKey.stream()
                    .map(it -> ConfigUtils.getFirstOptionalValue(List.of(it), Boolean.class).orElse(true))
                    .reduce(
                            (enabled, otherEnabled) -> enabled && otherEnabled)
                    .orElse(true);
        } else {
            jdbcDataSourceEnabled = config.persistenceUnits.values()
                    .stream()
                    .map(it -> it.datasource.orElse(null))
                    .filter(Objects::nonNull)
                    .map(dataSource -> {
                        var datasourceJdbcEnabledKeys = DataSourceUtil.dataSourcePropertyKeys(dataSource, "jdbc");
                        //We have to iterate over each key separately since quarkus.datasource."name".jdbc and quarkus.datasource.name.jdbc would not return the same result
                        return datasourceJdbcEnabledKeys.stream()
                                .map(it -> ConfigUtils.getFirstOptionalValue(List.of(it), Boolean.class).orElse(true))
                                .reduce(
                                        (enabled, otherEnabled) -> enabled && otherEnabled)
                                .orElse(true);
                    }).reduce((dataSourceJdbcEnabled, anotherDataSourceJdbcEnabled) -> dataSourceJdbcEnabled
                            && anotherDataSourceJdbcEnabled)
                    .orElse(true);
        }
        //We won't generate an implied PU if there are explicitly configured PUs
        if (actualXmlDescriptors.isEmpty() == false) {
            //when we have any explicitly provided Persistence Unit, disable the automatically generated ones.
            return ImpliedBlockingPersistenceUnitTypeBuildItem.none();
        }

        // If we have some blocking datasources defined, we can have an implied PU
        if (((jdbcDataSourcesBuildItem.size() == 0) || !jdbcDataSourceEnabled)
                && capabilities.isPresent(Capability.HIBERNATE_REACTIVE)) {
            // if we don't have any blocking datasources and Hibernate Reactive is present,
            // we don't want a blocking persistence unit
            return ImpliedBlockingPersistenceUnitTypeBuildItem.none();
        } else {
            // even if we don't have any JDBC datasource, we trigger the implied blocking persistence unit
            // to properly trigger error conditions and error messages to guide the user
            return ImpliedBlockingPersistenceUnitTypeBuildItem.generateImpliedPersistenceUnit();
        }
    }

This fix passes all unit & integration tests (and a new integration test for this specific case), and actually fixes the issue. If no jdbc datasource is used for hibernate it assumed a non blocking persistent unit. I admit the implementation could be better, but hey, it works.
I can open a PR for that if I'll just get any response from you guys.

@yrodiere
Copy link
Member

Please send a PR if it's not too much work, it'll be easier to determine what's going on with an actual diff.

@tomas1885
Copy link
Contributor Author

@yrodiere I opened an initial PR so you can "catch the drift" of the problem and suggested solution

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/agroal area/hibernate-reactive Hibernate Reactive area/persistence OBSOLETE, DO NOT USE kind/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants