Skip to content

Commit

Permalink
Add runtime configuration property quarkus.datasource.active
Browse files Browse the repository at this point in the history
  • Loading branch information
yrodiere committed Jan 17, 2024
1 parent 0f7ccfa commit 5bbae6f
Show file tree
Hide file tree
Showing 44 changed files with 602 additions and 247 deletions.
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
Expand Up @@ -3,13 +3,13 @@
import java.util.Map;
import java.util.Optional;

public class DataSourceSupport {
public class AgroalDataSourceSupport {

public final boolean disableSslSupport;
public final boolean mpMetricsPresent;
public final Map<String, Entry> entries;

public DataSourceSupport(boolean disableSslSupport, boolean mpMetricsPresent, Map<String, Entry> entries) {
public AgroalDataSourceSupport(boolean disableSslSupport, boolean mpMetricsPresent, Map<String, Entry> entries) {
this.disableSslSupport = disableSslSupport;
this.mpMetricsPresent = mpMetricsPresent;
this.entries = entries;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
@Recorder
public class AgroalRecorder {

public Supplier<DataSourceSupport> dataSourceSupportSupplier(DataSourceSupport dataSourceSupport) {
return new Supplier<DataSourceSupport>() {
public Supplier<AgroalDataSourceSupport> dataSourceSupportSupplier(AgroalDataSourceSupport agroalDataSourceSupport) {
return new Supplier<AgroalDataSourceSupport>() {
@Override
public DataSourceSupport get() {
return dataSourceSupport;
public AgroalDataSourceSupport get() {
return agroalDataSourceSupport;
}
};
}
Expand Down
Loading

0 comments on commit 5bbae6f

Please sign in to comment.