From 31d3cb78a5cf4e47a680944683b32a14f1c37b0f Mon Sep 17 00:00:00 2001 From: Zheng Feng Date: Sat, 17 Sep 2022 09:47:28 +0800 Subject: [PATCH] Introduce an option in narayana-jta for enabling XA recovery --- .../quarkus/agroal/runtime/DataSources.java | 26 ++++++++++++++----- .../jta/deployment/NarayanaJtaProcessor.java | 2 +- .../jta/runtime/NarayanaJtaProducers.java | 8 +++--- .../jta/runtime/NarayanaJtaRecorder.java | 6 +++-- .../TransactionManagerConfiguration.java | 6 +++++ 5 files changed, 36 insertions(+), 12 deletions(-) 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 9adbe0abf066c..28172208ff026 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 @@ -49,6 +49,7 @@ import io.quarkus.datasource.runtime.DataSourceRuntimeConfig; import io.quarkus.datasource.runtime.DataSourcesBuildTimeConfig; import io.quarkus.datasource.runtime.DataSourcesRuntimeConfig; +import io.quarkus.narayana.jta.runtime.TransactionManagerConfiguration; /** * This class is sort of a producer for {@link AgroalDataSource}. @@ -72,6 +73,7 @@ public class DataSources { private final DataSourcesRuntimeConfig dataSourcesRuntimeConfig; private final DataSourcesJdbcBuildTimeConfig dataSourcesJdbcBuildTimeConfig; private final DataSourcesJdbcRuntimeConfig dataSourcesJdbcRuntimeConfig; + private final TransactionManagerConfiguration transactionRuntimeConfig; private final TransactionManager transactionManager; private final XAResourceRecoveryRegistry xaResourceRecoveryRegistry; private final TransactionSynchronizationRegistry transactionSynchronizationRegistry; @@ -83,6 +85,7 @@ public class DataSources { public DataSources(DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig, DataSourcesRuntimeConfig dataSourcesRuntimeConfig, DataSourcesJdbcBuildTimeConfig dataSourcesJdbcBuildTimeConfig, DataSourcesJdbcRuntimeConfig dataSourcesJdbcRuntimeConfig, + TransactionManagerConfiguration transactionRuntimeConfig, TransactionManager transactionManager, XAResourceRecoveryRegistry xaResourceRecoveryRegistry, TransactionSynchronizationRegistry transactionSynchronizationRegistry, DataSourceSupport dataSourceSupport, @@ -91,6 +94,7 @@ public DataSources(DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig, this.dataSourcesRuntimeConfig = dataSourcesRuntimeConfig; this.dataSourcesJdbcBuildTimeConfig = dataSourcesJdbcBuildTimeConfig; this.dataSourcesJdbcRuntimeConfig = dataSourcesJdbcRuntimeConfig; + this.transactionRuntimeConfig = transactionRuntimeConfig; this.transactionManager = transactionManager; this.xaResourceRecoveryRegistry = xaResourceRecoveryRegistry; this.transactionSynchronizationRegistry = transactionSynchronizationRegistry; @@ -215,8 +219,10 @@ public AgroalDataSource doCreateDataSource(String dataSourceName) { .connectionFactoryConfiguration(); boolean mpMetricsPresent = dataSourceSupport.mpMetricsPresent; - applyNewConfiguration(dataSourceConfiguration, poolConfiguration, connectionFactoryConfiguration, driver, jdbcUrl, - dataSourceJdbcBuildTimeConfig, dataSourceRuntimeConfig, dataSourceJdbcRuntimeConfig, mpMetricsPresent); + applyNewConfiguration(dataSourceName, dataSourceConfiguration, poolConfiguration, connectionFactoryConfiguration, + driver, jdbcUrl, + dataSourceJdbcBuildTimeConfig, dataSourceRuntimeConfig, dataSourceJdbcRuntimeConfig, transactionRuntimeConfig, + mpMetricsPresent); if (dataSourceSupport.disableSslSupport) { agroalConnectionConfigurer.disableSslSupport(resolvedDbKind, dataSourceConfiguration); @@ -255,11 +261,12 @@ public AgroalDataSource doCreateDataSource(String dataSourceName) { return dataSource; } - private void applyNewConfiguration(AgroalDataSourceConfigurationSupplier dataSourceConfiguration, + private void applyNewConfiguration(String dataSourceName, AgroalDataSourceConfigurationSupplier dataSourceConfiguration, AgroalConnectionPoolConfigurationSupplier poolConfiguration, AgroalConnectionFactoryConfigurationSupplier connectionFactoryConfiguration, Class driver, String jdbcUrl, DataSourceJdbcBuildTimeConfig dataSourceJdbcBuildTimeConfig, DataSourceRuntimeConfig dataSourceRuntimeConfig, - DataSourceJdbcRuntimeConfig dataSourceJdbcRuntimeConfig, boolean mpMetricsPresent) { + DataSourceJdbcRuntimeConfig dataSourceJdbcRuntimeConfig, TransactionManagerConfiguration transactionRuntimeConfig, + boolean mpMetricsPresent) { connectionFactoryConfiguration.jdbcUrl(jdbcUrl); connectionFactoryConfiguration.connectionProviderClass(driver); connectionFactoryConfiguration.trackJdbcResources(dataSourceJdbcRuntimeConfig.detectStatementLeaks); @@ -274,8 +281,15 @@ private void applyNewConfiguration(AgroalDataSourceConfigurationSupplier dataSou TransactionIntegration txIntegration = new NarayanaTransactionIntegration(transactionManager, transactionSynchronizationRegistry, null, false, dataSourceJdbcBuildTimeConfig.transactions == io.quarkus.agroal.runtime.TransactionIntegration.XA - ? xaResourceRecoveryRegistry - : null); + && transactionRuntimeConfig.enableRecovery + ? xaResourceRecoveryRegistry + : null); + if (dataSourceJdbcBuildTimeConfig.transactions == io.quarkus.agroal.runtime.TransactionIntegration.XA + && !transactionRuntimeConfig.enableRecovery) { + log.warnv( + "Datasource {0} enables XA but transaction recovery is not enabled. Please enable transaction recovery by setting quarkus.transaction-manager.enable-recovery=true, otherwise data may be lost if the application is terminated abruptly", + dataSourceName); + } poolConfiguration.transactionIntegration(txIntegration); } diff --git a/extensions/narayana-jta/deployment/src/main/java/io/quarkus/narayana/jta/deployment/NarayanaJtaProcessor.java b/extensions/narayana-jta/deployment/src/main/java/io/quarkus/narayana/jta/deployment/NarayanaJtaProcessor.java index abd0b310441cb..2ca5d25e3373c 100644 --- a/extensions/narayana-jta/deployment/src/main/java/io/quarkus/narayana/jta/deployment/NarayanaJtaProcessor.java +++ b/extensions/narayana-jta/deployment/src/main/java/io/quarkus/narayana/jta/deployment/NarayanaJtaProcessor.java @@ -82,7 +82,7 @@ public void build(NarayanaJtaRecorder recorder, BuildProducer runtimeInit, BuildProducer feature, TransactionManagerConfiguration transactions, ShutdownContextBuildItem shutdownContextBuildItem) { - recorder.handleShutdown(shutdownContextBuildItem); + recorder.handleShutdown(shutdownContextBuildItem, transactions); feature.produce(new FeatureBuildItem(Feature.NARAYANA_JTA)); additionalBeans.produce(new AdditionalBeanBuildItem(NarayanaJtaProducers.class)); additionalBeans.produce(new AdditionalBeanBuildItem(CDIDelegatingTransactionManager.class)); diff --git a/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/NarayanaJtaProducers.java b/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/NarayanaJtaProducers.java index abfb7d0d36f97..77bbaa4f0f27d 100644 --- a/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/NarayanaJtaProducers.java +++ b/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/NarayanaJtaProducers.java @@ -34,10 +34,12 @@ public javax.transaction.UserTransaction userTransaction() { @Produces @Singleton - public XAResourceRecoveryRegistry xaResourceRecoveryRegistry() { + public XAResourceRecoveryRegistry xaResourceRecoveryRegistry(TransactionManagerConfiguration config) { RecoveryManagerService recoveryManagerService = new RecoveryManagerService(); - recoveryManagerService.create(); - recoveryManagerService.start(); + if (config.enableRecovery) { + recoveryManagerService.create(); + recoveryManagerService.start(); + } return recoveryManagerService; } diff --git a/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/NarayanaJtaRecorder.java b/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/NarayanaJtaRecorder.java index 82d2e61b95ec4..ac859f3502391 100644 --- a/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/NarayanaJtaRecorder.java +++ b/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/NarayanaJtaRecorder.java @@ -86,11 +86,13 @@ public void setConfig(final TransactionManagerConfiguration transactions) { .setXaResourceOrphanFilterClassNames(transactions.xaResourceOrphanFilters); } - public void handleShutdown(ShutdownContext context) { + public void handleShutdown(ShutdownContext context, TransactionManagerConfiguration transactions) { context.addLastShutdownTask(new Runnable() { @Override public void run() { - RecoveryManager.manager().terminate(true); + if (transactions.enableRecovery) { + RecoveryManager.manager().terminate(true); + } TransactionReaper.terminate(false); } }); diff --git a/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/TransactionManagerConfiguration.java b/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/TransactionManagerConfiguration.java index b4f8ab1ee8cc1..be182bd3d76cc 100644 --- a/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/TransactionManagerConfiguration.java +++ b/extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/TransactionManagerConfiguration.java @@ -32,6 +32,12 @@ public final class TransactionManagerConfiguration { @ConfigItem(defaultValue = "ObjectStore") public String objectStoreDirectory; + /** + * Start the recovery service on startup. + */ + @ConfigItem(defaultValue = "false") + public boolean enableRecovery; + /** * The list of recovery modules */