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

Add runtime configuration property quarkus.datasource.active #38108

Merged
merged 3 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/src/main/asciidoc/cdi.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ Client proxies allow for:
* Circular dependencies in the dependency graph. Having circular dependencies is often an indication that a redesign should be considered, but sometimes it's inevitable.
* In rare cases it's practical to destroy the beans manually. A direct injected reference would lead to a stale bean instance.


[[ok-you-said-that-there-are-several-kinds-of-beans]]
== OK. You said that there are several kinds of beans?

Yes. In general, we distinguish:
Expand Down
1 change: 1 addition & 0 deletions docs/src/main/asciidoc/config-reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ By default, Quarkus provides three profiles, that activate automatically in cert
* *test* - Activated when running tests
* *prod* - The default profile when not running in development or test mode

[[custom-profiles]]
=== Custom Profiles

It is also possible to create additional profiles and activate them with the `quarkus.profile` configuration property. A
Expand Down
93 changes: 93 additions & 0 deletions docs/src/main/asciidoc/datasource.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,99 @@ AgroalDataSource usersDataSource;
AgroalDataSource inventoryDataSource;
----

[[datasource-active]]
=== Activate/deactivate datasources

If a datasource is configured at build time,
by default it is active at runtime,
that is Quarkus will start the corresponding JDBC connection pool or reactive client on application startup.

To deactivate a datasource at runtime, set `quarkus.datasource[.optional name].active` to `false`.
Then Quarkus will not start the corresponding JDBC connection pool or reactive client on application startup.
Any attempt to use the corresponding datasource at runtime will fail with a clear error message.

This is in particular useful when you want an application to be able
to use one of a pre-determined set of datasources at runtime.

[WARNING]
====
If another Quarkus extension relies on an inactive datasource,
that extension might fail to start.

In such case, you will need to deactivate that other extension too.
For example see xref:hibernate-orm.adoc#persistence-unit-active[here for Hibernate ORM].
====

For example, with the following configuration:

[source,properties]
----
quarkus.datasource."pg".db-kind=postgres
quarkus.datasource."pg".active=false
quarkus.datasource."pg".jdbc.url=jdbc:postgresql:///your_database

quarkus.datasource."oracle".db-kind=oracle
quarkus.datasource."oracle".active=false
quarkus.datasource."oracle".jdbc.url=jdbc:oracle:///your_database
----

Setting `quarkus.datasource."pg".active=true` xref:config-reference.adoc#configuration-sources[at runtime]
will make only the PostgreSQL datasource available,
and setting `quarkus.datasource."oracle".active=true` at runtime
will make only the Oracle datasource available.

[TIP]
====
xref:config-reference.adoc#custom-profiles[Custom configuration profiles] can help simplify such a setup.
By appending the following profile-specific configuration to the one above,
you can select a persistence unit/datasource at runtime simply by
xref:config-reference.adoc#multiple-profiles[setting `quarkus.profile`]:
`quarkus.profile=prod,pg` or `quarkus.profile=prod,oracle`.

[source,properties]
----
%pg.quarkus.hibernate-orm."pg".active=true
%pg.quarkus.datasource."pg".active=true
# Add any pg-related runtime configuration here, prefixed with "%pg."

%oracle.quarkus.hibernate-orm."oracle".active=true
%oracle.quarkus.datasource."oracle".active=true
# Add any pg-related runtime configuration here, prefixed with "%pg."
----
====

[TIP]
====
It can also be useful to define a xref:cdi.adoc#ok-you-said-that-there-are-several-kinds-of-beans[CDI bean producer] redirecting to the currently active datasource,
like this:

[source,java,indent=0]
----
public class MyProducer {
@Inject
DataSourceSupport dataSourceSupport;

@Inject
@DataSource("pg")
AgroalDataSource pgDataSourceBean;

@Inject
@DataSource("oracle")
AgroalDataSource oracleDataSourceBean;

@Produces
@ApplicationScoped
public AgroalDataSource dataSource() {
if (dataSourceSupport.getInactiveNames().contains("pg")) {
return oracleDataSourceBean;
} else {
return pgDataSourceBean;
}
}
}
----
====

== Datasource integrations

=== Datasource health check
Expand Down
92 changes: 92 additions & 0 deletions docs/src/main/asciidoc/hibernate-orm.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,98 @@ You can inject the `EntityManagerFactory` of a named persistence unit using the
EntityManagerFactory entityManagerFactory;
----

[[persistence-unit-active]]
=== Activate/deactivate persistence units

If a persistence unit is configured at build time,
by default it is active at runtime,
that is Quarkus will start the corresponding Hibernate ORM `SessionFactory` on application startup.

To deactivate a persistence unit at runtime, set `quarkus.hibernate-orm[.optional name].active` to `false`.
Then Quarkus will not start the corresponding Hibernate ORM `SessionFactory` on application startup.
Any attempt to use the corresponding persistence unit at runtime will fail with a clear error message.

This is in particular useful when you want an application to be able
to xref:datasource.adoc#datasource-active[use one of a pre-determined set of datasources at runtime].

For example, with the following configuration:

[source,properties]
----
quarkus.hibernate-orm."pg".packages=org.acme.model.shared
quarkus.hibernate-orm."pg".datasource=pg
quarkus.hibernate-orm."pg".database.generation=drop-and-create
quarkus.hibernate-orm."pg".active=false
quarkus.datasource."pg".db-kind=h2
quarkus.datasource."pg".active=false
quarkus.datasource."pg".jdbc.url=jdbc:postgresql:///your_database

quarkus.hibernate-orm."oracle".packages=org.acme.model.shared
quarkus.hibernate-orm."oracle".datasource=oracle
quarkus.hibernate-orm."oracle".database.generation=drop-and-create
quarkus.hibernate-orm."oracle".active=false
quarkus.datasource."oracle".db-kind=oracle
quarkus.datasource."oracle".active=false
quarkus.datasource."oracle".jdbc.url=jdbc:oracle:///your_database
----

xref:config-reference.adoc#configuration-sources[Setting] `quarkus.hibernate-orm."pg".active=true` and `quarkus.datasource."pg".active=true` at runtime
will make only the PostgreSQL persistence unit and datasource available,
and setting `quarkus.hibernate-orm."oracle".active=true` and `quarkus.datasource."oracle".active=true` at runtime
will make only the Oracle persistence unit and datasource available.

[TIP]
====
xref:config-reference.adoc#custom-profiles[Custom configuration profiles] can help simplify such a setup.
By appending the following profile-specific configuration to the one above,
you can select a persistence unit/datasource at runtime simply by
xref:config-reference.adoc#multiple-profiles[setting `quarkus.profile`]:
`quarkus.profile=prod,pg` or `quarkus.profile=prod,oracle`.

[source,properties]
----
%pg.quarkus.hibernate-orm."pg".active=true
%pg.quarkus.datasource."pg".active=true
# Add any pg-related runtime configuration here, prefixed with "%pg."

%oracle.quarkus.hibernate-orm."oracle".active=true
%oracle.quarkus.datasource."oracle".active=true
# Add any pg-related runtime configuration here, prefixed with "%pg."
----
====

[TIP]
====
It can also be useful to define a xref:cdi.adoc#ok-you-said-that-there-are-several-kinds-of-beans[CDI bean producer] redirecting to the currently active persistence unit,
like this:

[source,java,indent=0]
----
public class MyProducer {
@Inject
DataSourceSupport dataSourceSupport;

@Inject
@PersistenceUnit("pg")
Session pgSessionBean;

@Inject
@PersistenceUnit("oracle")
Session oracleSessionBean;

@Produces
@ApplicationScoped
public Session session() {
if (dataSourceSupport.getInactiveNames().contains("pg")) {
return oracleSessionBean;
} else {
return pgSessionBean;
}
}
}
----
====

[[persistence-xml]]
== Setting up and configuring Hibernate ORM with a `persistence.xml`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@
import io.agroal.api.AgroalDataSource;
import io.agroal.api.AgroalPoolInterceptor;
import io.quarkus.agroal.DataSource;
import io.quarkus.agroal.runtime.AgroalDataSourceSupport;
import io.quarkus.agroal.runtime.AgroalDataSourcesInitializer;
import io.quarkus.agroal.runtime.AgroalRecorder;
import io.quarkus.agroal.runtime.DataSourceJdbcBuildTimeConfig;
import io.quarkus.agroal.runtime.DataSourceSupport;
import io.quarkus.agroal.runtime.DataSources;
import io.quarkus.agroal.runtime.DataSourcesJdbcBuildTimeConfig;
import io.quarkus.agroal.runtime.JdbcDriver;
Expand Down Expand Up @@ -202,20 +202,20 @@ private static void validateBuildTimeConfig(AggregatedDataSourceBuildTimeConfigB
}
}

private DataSourceSupport getDataSourceSupport(
private AgroalDataSourceSupport getDataSourceSupport(
List<AggregatedDataSourceBuildTimeConfigBuildItem> aggregatedBuildTimeConfigBuildItems,
SslNativeConfigBuildItem sslNativeConfig, Capabilities capabilities) {
Map<String, DataSourceSupport.Entry> dataSourceSupportEntries = new HashMap<>();
Map<String, AgroalDataSourceSupport.Entry> dataSourceSupportEntries = new HashMap<>();
for (AggregatedDataSourceBuildTimeConfigBuildItem aggregatedDataSourceBuildTimeConfig : aggregatedBuildTimeConfigBuildItems) {
String dataSourceName = aggregatedDataSourceBuildTimeConfig.getName();
dataSourceSupportEntries.put(dataSourceName,
new DataSourceSupport.Entry(dataSourceName, aggregatedDataSourceBuildTimeConfig.getDbKind(),
new AgroalDataSourceSupport.Entry(dataSourceName, aggregatedDataSourceBuildTimeConfig.getDbKind(),
aggregatedDataSourceBuildTimeConfig.getDataSourceConfig().dbVersion(),
aggregatedDataSourceBuildTimeConfig.getResolvedDriverClass(),
aggregatedDataSourceBuildTimeConfig.isDefault()));
}

return new DataSourceSupport(sslNativeConfig.isExplicitlyDisabled(),
return new AgroalDataSourceSupport(sslNativeConfig.isExplicitlyDisabled(),
capabilities.isPresent(Capability.METRICS), dataSourceSupportEntries);
}

Expand Down Expand Up @@ -247,10 +247,11 @@ void generateDataSourceSupportBean(AgroalRecorder recorder,
unremovableBeans.produce(UnremovableBeanBuildItem.beanTypes(AgroalPoolInterceptor.class));

// create the DataSourceSupport bean that DataSourceProducer uses as a dependency
DataSourceSupport dataSourceSupport = getDataSourceSupport(aggregatedBuildTimeConfigBuildItems, sslNativeConfig,
AgroalDataSourceSupport agroalDataSourceSupport = getDataSourceSupport(aggregatedBuildTimeConfigBuildItems,
sslNativeConfig,
capabilities);
syntheticBeanBuildItemBuildProducer.produce(SyntheticBeanBuildItem.configure(DataSourceSupport.class)
.supplier(recorder.dataSourceSupportSupplier(dataSourceSupport))
syntheticBeanBuildItemBuildProducer.produce(SyntheticBeanBuildItem.configure(AgroalDataSourceSupport.class)
.supplier(recorder.dataSourceSupportSupplier(agroalDataSourceSupport))
.unremovable()
.done());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package io.quarkus.agroal.test;

import jakarta.inject.Inject;

import org.eclipse.microprofile.metrics.Counter;
import org.eclipse.microprofile.metrics.Gauge;
import org.eclipse.microprofile.metrics.MetricID;
import org.eclipse.microprofile.metrics.MetricRegistry;
import org.eclipse.microprofile.metrics.Tag;
import org.eclipse.microprofile.metrics.annotation.RegistryType;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.test.QuarkusUnitTest;

public class AgroalMetricsConfigActiveFalseTest {

@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.withConfigurationResource("application-metrics-enabled.properties")
.overrideConfigKey("quarkus.datasource.active", "false")
.overrideConfigKey("quarkus.datasource.ds1.active", "false");

@Inject
@RegistryType(type = MetricRegistry.Type.VENDOR)
MetricRegistry registry;

@Test
public void testMetricsOfDefaultDS() {
Counter acquireCount = registry.getCounters()
.get(new MetricID("agroal.acquire.count", new Tag("datasource", "default")));
Gauge<?> maxUsed = registry.getGauges()
.get(new MetricID("agroal.max.used.count", new Tag("datasource", "default")));

Assertions.assertNull(acquireCount, "Agroal metrics should not be registered for deactivated datasources eagerly");
Assertions.assertNull(maxUsed, "Agroal metrics should not be registered for deactivated datasources eagerly");
}

@Test
public void testMetricsOfDs1() {
Counter acquireCount = registry.getCounters().get(new MetricID("agroal.acquire.count",
new Tag("datasource", "ds1")));
Gauge<?> maxUsed = registry.getGauges().get(new MetricID("agroal.max.used.count",
new Tag("datasource", "ds1")));

Assertions.assertNull(acquireCount, "Agroal metrics should not be registered for deactivated datasources eagerly");
Assertions.assertNull(maxUsed, "Agroal metrics should not be registered for deactivated datasources eagerly");
}

}
Loading
Loading