diff --git a/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSources.java b/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSources.java index 4996ee0ce328f4..10415d485313d9 100644 --- a/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSources.java +++ b/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSources.java @@ -140,6 +140,10 @@ public AgroalDataSource getDataSource(String dataSourceName) { return dataSource; } + public boolean isDataSourceActive(String dataSourceName) { + return getDataSourceIfActiveOrNull(dataSourceName) != null; + } + public Optional getDataSourceIfActive(String dataSourceName) { return Optional.ofNullable(getDataSourceIfActiveOrNull(dataSourceName)); } diff --git a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayDataSourceRuntimeConfig.java b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayDataSourceRuntimeConfig.java index 726ada0de89fd2..2e9d9aa3dd35ee 100644 --- a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayDataSourceRuntimeConfig.java +++ b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayDataSourceRuntimeConfig.java @@ -25,8 +25,8 @@ public static FlywayDataSourceRuntimeConfig defaultConfig() { /** * Flag to activate/deactivate Flyway for a specific datasource at runtime. */ - @ConfigItem(defaultValue = "true") - public boolean active = true; + @ConfigItem(defaultValueDocumentation = "'true' if the datasource is active; 'false' otherwise") + public Optional active = Optional.empty(); /** * The maximum number of retries when attempting to connect to the database. diff --git a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRecorder.java b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRecorder.java index 71d8b011cf18d1..2a61b6f7cd9f8c 100644 --- a/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRecorder.java +++ b/extensions/flyway/runtime/src/main/java/io/quarkus/flyway/runtime/FlywayRecorder.java @@ -106,7 +106,9 @@ public void doStartActions(String dataSourceName) { FlywayDataSourceRuntimeConfig flywayDataSourceRuntimeConfig = config.getValue() .getConfigForDataSourceName(dataSourceName); - if (!config.getValue().getConfigForDataSourceName(dataSourceName).active) { + if (!flywayDataSourceRuntimeConfig.active + // If not specified explicitly, Flyway is active when the datasource itself is active. + .orElseGet(() -> Arc.container().instance(DataSources.class).get().isDataSourceActive(dataSourceName))) { return; } diff --git a/extensions/liquibase/deployment/src/main/java/io/quarkus/liquibase/deployment/LiquibaseProcessor.java b/extensions/liquibase/deployment/src/main/java/io/quarkus/liquibase/deployment/LiquibaseProcessor.java index 52b2e76afd401a..89e923fdc98872 100644 --- a/extensions/liquibase/deployment/src/main/java/io/quarkus/liquibase/deployment/LiquibaseProcessor.java +++ b/extensions/liquibase/deployment/src/main/java/io/quarkus/liquibase/deployment/LiquibaseProcessor.java @@ -303,10 +303,13 @@ ServiceStartBuildItem startLiquibase(LiquibaseRecorder recorder, BuildProducer initializationCompleteBuildItem, BuildProducer schemaReadyBuildItem) { - recorder.doStartActions(); + Set dataSourceNames = getDataSourceNames(jdbcDataSourceBuildItems); + for (String dataSourceName : dataSourceNames) { + recorder.doStartActions(dataSourceName); + } // once we are done running the migrations, we produce a build item indicating that the // schema is "ready" - schemaReadyBuildItem.produce(new JdbcDataSourceSchemaReadyBuildItem(getDataSourceNames(jdbcDataSourceBuildItems))); + schemaReadyBuildItem.produce(new JdbcDataSourceSchemaReadyBuildItem(dataSourceNames)); initializationCompleteBuildItem.produce(new InitTaskCompletedBuildItem("liquibase")); return new ServiceStartBuildItem("liquibase"); diff --git a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseRecorder.java b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseRecorder.java index d48296e144fb17..3f2e43dcbf6897 100644 --- a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseRecorder.java +++ b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseRecorder.java @@ -1,20 +1,21 @@ package io.quarkus.liquibase.runtime; +import java.lang.annotation.Annotation; +import java.util.Locale; import java.util.function.Function; import javax.sql.DataSource; -import io.quarkus.datasource.common.runtime.DataSourceUtil; -import io.quarkus.runtime.configuration.ConfigurationException; -import jakarta.enterprise.inject.Any; +import jakarta.enterprise.inject.Default; import jakarta.enterprise.inject.UnsatisfiedResolutionException; import io.quarkus.agroal.runtime.DataSources; import io.quarkus.agroal.runtime.UnconfiguredDataSource; import io.quarkus.arc.Arc; -import io.quarkus.arc.InjectableInstance; import io.quarkus.arc.InstanceHandle; import io.quarkus.arc.SyntheticCreationalContext; +import io.quarkus.datasource.common.runtime.DataSourceUtil; +import io.quarkus.liquibase.LiquibaseDataSource.LiquibaseDataSourceLiteral; import io.quarkus.liquibase.LiquibaseFactory; import io.quarkus.runtime.RuntimeValue; import io.quarkus.runtime.annotations.Recorder; @@ -42,7 +43,8 @@ public LiquibaseFactory apply(SyntheticCreationalContext conte throw DataSourceUtil.dataSourceNotConfigured(dataSourceName); } } catch (RuntimeException e) { - throw new ConfigurationException(String.format("Unable to find datasource '%s' for Liquibase: %s", + throw new UnsatisfiedResolutionException(String.format(Locale.ROOT, + "Unable to find datasource '%s' for Liquibase: %s", dataSourceName, e.getMessage()), e); } @@ -52,49 +54,53 @@ public LiquibaseFactory apply(SyntheticCreationalContext conte }; } - public void doStartActions() { + public void doStartActions(String dataSourceName) { if (!config.getValue().enabled) { return; } + // Liquibase is active when the datasource itself is active. + if (!Arc.container().instance(DataSources.class).get().isDataSourceActive(dataSourceName)) { + return; + } + InstanceHandle liquibaseFactoryHandle = Arc.container().instance(LiquibaseFactory.class, + getLiquibaseFactoryQualifier(dataSourceName)); try { - InjectableInstance liquibaseFactoryInstance = Arc.container() - .select(LiquibaseFactory.class, Any.Literal.INSTANCE); - if (liquibaseFactoryInstance.isUnsatisfied()) { + LiquibaseFactory liquibaseFactory = liquibaseFactoryHandle.get(); + var config = liquibaseFactory.getConfiguration(); + if (!config.cleanAtStart && !config.migrateAtStart) { return; } - - for (InstanceHandle liquibaseFactoryHandle : liquibaseFactoryInstance.handles()) { - try { - LiquibaseFactory liquibaseFactory = liquibaseFactoryHandle.get(); - var config = liquibaseFactory.getConfiguration(); - if (!config.cleanAtStart && !config.migrateAtStart) { - continue; - } - try (Liquibase liquibase = liquibaseFactory.createLiquibase()) { - if (config.cleanAtStart) { - liquibase.dropAll(); - } - if (config.migrateAtStart) { - var lockService = LockServiceFactory.getInstance() - .getLockService(liquibase.getDatabase()); - lockService.waitForLock(); - try { - if (config.validateOnMigrate) { - liquibase.validate(); - } - liquibase.update(liquibaseFactory.createContexts(), liquibaseFactory.createLabels()); - } finally { - lockService.releaseLock(); - } + try (Liquibase liquibase = liquibaseFactory.createLiquibase()) { + if (config.cleanAtStart) { + liquibase.dropAll(); + } + if (config.migrateAtStart) { + var lockService = LockServiceFactory.getInstance() + .getLockService(liquibase.getDatabase()); + lockService.waitForLock(); + try { + if (config.validateOnMigrate) { + liquibase.validate(); } + liquibase.update(liquibaseFactory.createContexts(), liquibaseFactory.createLabels()); + } finally { + lockService.releaseLock(); } - } catch (UnsatisfiedResolutionException e) { - //ignore, the DS is not configured } } + } catch (UnsatisfiedResolutionException e) { + //ignore, the DS is not configured } catch (Exception e) { throw new IllegalStateException("Error starting Liquibase", e); } } + + private static Annotation getLiquibaseFactoryQualifier(String dataSourceName) { + if (DataSourceUtil.isDefault(dataSourceName)) { + return Default.Literal.INSTANCE; + } + + return LiquibaseDataSourceLiteral.of(dataSourceName); + } }