From 263866c03ab74f0104e88d78b0769eb3f16b37f0 Mon Sep 17 00:00:00 2001 From: Arnold Galovics Date: Wed, 11 Dec 2024 15:34:21 +0100 Subject: [PATCH] FINERACT-2081: Avoid creating unnecessary connection pools --- .../GlobalConfigurationValidationService.java | 2 ++ .../core/service/JdbcTemplateFactory.java | 11 +++----- .../migration/TenantDataSourceFactory.java | 3 +-- ...alEventConfigurationValidationService.java | 2 ++ .../TenantDatabaseUpgradeService.java | 26 ++++++++++--------- .../jobs/service/StuckJobListener.java | 2 +- .../apache/fineract/TestConfiguration.java | 10 +++---- .../core/LiquibaseStepDefinitions.java | 5 ++-- 8 files changed, 32 insertions(+), 29 deletions(-) diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/service/GlobalConfigurationValidationService.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/service/GlobalConfigurationValidationService.java index b11ea577235..f4018e2b0ef 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/service/GlobalConfigurationValidationService.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/service/GlobalConfigurationValidationService.java @@ -26,6 +26,7 @@ import org.apache.fineract.infrastructure.configuration.exception.GlobalConfigurationException; import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.service.JdbcTemplateFactory; +import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.infrastructure.core.service.tenant.TenantDetailsService; import org.springframework.beans.factory.InitializingBean; import org.springframework.jdbc.core.JdbcTemplate; @@ -50,6 +51,7 @@ private void validateGlobalConfigurationNames() { if (isNotEmpty(tenants)) { for (FineractPlatformTenant tenant : tenants) { + ThreadLocalContextUtil.setTenant(tenant); validateGlobalConfigurationForIndividualTenant(tenant); } } diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/JdbcTemplateFactory.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/JdbcTemplateFactory.java index b3c3cda9147..eeab9f18515 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/JdbcTemplateFactory.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/JdbcTemplateFactory.java @@ -18,10 +18,9 @@ */ package org.apache.fineract.infrastructure.core.service; -import javax.sql.DataSource; import lombok.RequiredArgsConstructor; import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; -import org.apache.fineract.infrastructure.core.service.migration.TenantDataSourceFactory; +import org.apache.fineract.infrastructure.core.service.database.RoutingDataSource; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Component; @@ -30,15 +29,13 @@ @Component public class JdbcTemplateFactory { - private final TenantDataSourceFactory tenantDataSourceFactory; + private final RoutingDataSource routingDataSource; public JdbcTemplate create(FineractPlatformTenant tenant) { - DataSource tenantDataSource = tenantDataSourceFactory.create(tenant); - return new JdbcTemplate(tenantDataSource); + return new JdbcTemplate(routingDataSource); } public NamedParameterJdbcTemplate createNamedParameterJdbcTemplate(FineractPlatformTenant tenant) { - DataSource tenantDataSource = tenantDataSourceFactory.create(tenant); - return new NamedParameterJdbcTemplate(tenantDataSource); + return new NamedParameterJdbcTemplate(routingDataSource); } } diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/migration/TenantDataSourceFactory.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/migration/TenantDataSourceFactory.java index 17e66ed02c8..938df631519 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/migration/TenantDataSourceFactory.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/migration/TenantDataSourceFactory.java @@ -22,7 +22,6 @@ import static org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection.toProtocol; import com.zaxxer.hikari.HikariDataSource; -import javax.sql.DataSource; import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection; import org.apache.fineract.infrastructure.core.service.database.DatabasePasswordEncryptor; @@ -48,7 +47,7 @@ public TenantDataSourceFactory(@Qualifier("hikariTenantDataSource") HikariDataSo this.databasePasswordEncryptor = databasePasswordEncryptor; } - public DataSource create(FineractPlatformTenant tenant) { + public HikariDataSource create(FineractPlatformTenant tenant) { HikariDataSource dataSource = new HikariDataSource(); dataSource.setDriverClassName(tenantDataSource.getDriverClassName()); dataSource.setDataSourceProperties(tenantDataSource.getDataSourceProperties()); diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationService.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationService.java index e363fed1e89..1e384d59cf7 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationService.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationService.java @@ -30,6 +30,7 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.service.JdbcTemplateFactory; +import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.infrastructure.core.service.tenant.TenantDetailsService; import org.apache.fineract.infrastructure.event.business.domain.BulkBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent; @@ -62,6 +63,7 @@ private void validateEventConfigurationForAllTenants() throws ExternalEventConfi if (isNotEmpty(tenants)) { for (FineractPlatformTenant tenant : tenants) { + ThreadLocalContextUtil.setTenant(tenant); validateEventConfigurationForIndividualTenant(tenant, eventClasses); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/migration/TenantDatabaseUpgradeService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/migration/TenantDatabaseUpgradeService.java index bdef1eb2d59..14aae50394b 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/migration/TenantDatabaseUpgradeService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/migration/TenantDatabaseUpgradeService.java @@ -21,6 +21,7 @@ import static org.apache.commons.collections4.CollectionUtils.isNotEmpty; import static org.apache.commons.lang3.StringUtils.isNotBlank; +import com.zaxxer.hikari.HikariDataSource; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -179,19 +180,20 @@ private ThreadPoolTaskExecutor createTenantUpgradeThreadPoolTaskExecutor() { */ private void upgradeIndividualTenant(FineractPlatformTenant tenant) throws LiquibaseException { log.info("Upgrade for tenant {} has started", tenant.getTenantIdentifier()); - DataSource tenantDataSource = tenantDataSourceFactory.create(tenant); - // 'initial_switch' and 'custom_changelog' contexts should be controlled by the application configuration - // settings, and we should not use them to control the script order - if (databaseStateVerifier.isFirstLiquibaseMigration(tenantDataSource)) { - ExtendedSpringLiquibase liquibase = liquibaseFactory.create(tenantDataSource, TENANT_DB_CONTEXT, CUSTOM_CHANGELOG_CONTEXT, - INITIAL_SWITCH_CONTEXT, tenant.getTenantIdentifier()); - applyInitialLiquibase(tenantDataSource, liquibase, tenant.getTenantIdentifier(), - (ds) -> !databaseStateVerifier.isTenantOnLatestUpgradableVersion(ds)); + try (HikariDataSource tenantDataSource = tenantDataSourceFactory.create(tenant)) { + // 'initial_switch' and 'custom_changelog' contexts should be controlled by the application configuration + // settings, and we should not use them to control the script order + if (databaseStateVerifier.isFirstLiquibaseMigration(tenantDataSource)) { + ExtendedSpringLiquibase liquibase = liquibaseFactory.create(tenantDataSource, TENANT_DB_CONTEXT, CUSTOM_CHANGELOG_CONTEXT, + INITIAL_SWITCH_CONTEXT, tenant.getTenantIdentifier()); + applyInitialLiquibase(tenantDataSource, liquibase, tenant.getTenantIdentifier(), + (ds) -> !databaseStateVerifier.isTenantOnLatestUpgradableVersion(ds)); + } + SpringLiquibase tenantLiquibase = liquibaseFactory.create(tenantDataSource, TENANT_DB_CONTEXT, CUSTOM_CHANGELOG_CONTEXT, + tenant.getTenantIdentifier()); + tenantLiquibase.afterPropertiesSet(); + log.info("Upgrade for tenant {} has finished", tenant.getTenantIdentifier()); } - SpringLiquibase tenantLiquibase = liquibaseFactory.create(tenantDataSource, TENANT_DB_CONTEXT, CUSTOM_CHANGELOG_CONTEXT, - tenant.getTenantIdentifier()); - tenantLiquibase.afterPropertiesSet(); - log.info("Upgrade for tenant {} has finished", tenant.getTenantIdentifier()); } private void applyInitialLiquibase(DataSource dataSource, ExtendedSpringLiquibase liquibase, String id, diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/StuckJobListener.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/StuckJobListener.java index 16998a3c897..21051c12ba0 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/StuckJobListener.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/StuckJobListener.java @@ -59,11 +59,11 @@ public void onApplicationEvent(ContextRefreshedEvent event) { if (!jobRegistry.getJobNames().isEmpty()) { List allTenants = tenantDetailsService.findAllTenants(); allTenants.forEach(tenant -> { + ThreadLocalContextUtil.setTenant(tenant); NamedParameterJdbcTemplate namedParameterJdbcTemplate = jdbcTemplateFactory.createNamedParameterJdbcTemplate(tenant); List stuckJobNames = jobExecutionRepository.getStuckJobNames(namedParameterJdbcTemplate); if (!stuckJobNames.isEmpty()) { try { - ThreadLocalContextUtil.setTenant(tenant); HashMap businessDates = businessDateReadPlatformService.getBusinessDates(); ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT); ThreadLocalContextUtil.setBusinessDates(businessDates); diff --git a/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java b/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java index 8dc6f8efa9a..aa6a210aa1b 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java +++ b/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java @@ -24,7 +24,6 @@ import com.zaxxer.hikari.HikariDataSource; import java.util.List; -import javax.sql.DataSource; import liquibase.change.custom.CustomTaskChange; import okhttp3.OkHttpClient; import org.apache.fineract.infrastructure.core.config.FineractProperties; @@ -33,6 +32,7 @@ import org.apache.fineract.infrastructure.core.service.database.DatabasePasswordEncryptor; import org.apache.fineract.infrastructure.core.service.database.DatabaseType; import org.apache.fineract.infrastructure.core.service.database.DatabaseTypeResolver; +import org.apache.fineract.infrastructure.core.service.database.RoutingDataSource; import org.apache.fineract.infrastructure.core.service.migration.ExtendedSpringLiquibaseFactory; import org.apache.fineract.infrastructure.core.service.migration.TenantDataSourceFactory; import org.apache.fineract.infrastructure.core.service.migration.TenantDatabaseStateVerifier; @@ -94,8 +94,8 @@ public TenantDataSourceFactory tenantDataSourceFactory(DatabasePasswordEncryptor return new TenantDataSourceFactory(null, databasePasswordEncryptor) { @Override - public DataSource create(FineractPlatformTenant tenant) { - return mock(DataSource.class); + public HikariDataSource create(FineractPlatformTenant tenant) { + return mock(HikariDataSource.class); } }; } @@ -111,8 +111,8 @@ public HikariDataSource tenantDataSource() { * DataSource with Mockito RETURNS_MOCKS black magic. */ @Bean - public DataSource hikariTenantDataSource() { - HikariDataSource mockDataSource = mock(HikariDataSource.class, Mockito.RETURNS_MOCKS); + public RoutingDataSource hikariTenantDataSource() { + RoutingDataSource mockDataSource = mock(RoutingDataSource.class, Mockito.RETURNS_MOCKS); return mockDataSource; } diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/LiquibaseStepDefinitions.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/LiquibaseStepDefinitions.java index 2384974977a..e838b6e8e31 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/LiquibaseStepDefinitions.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/LiquibaseStepDefinitions.java @@ -31,6 +31,7 @@ import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions; +import com.zaxxer.hikari.HikariDataSource; import io.cucumber.java8.En; import java.util.Arrays; import java.util.List; @@ -66,7 +67,7 @@ public class LiquibaseStepDefinitions implements En { private TenantDatabaseUpgradeService tenantDatabaseUpgradeService; private List allTenants; private SchemaUpgradeNeededException executionException; - private DataSource defaultTenantDataSource; + private HikariDataSource defaultTenantDataSource; private Environment environment; public LiquibaseStepDefinitions() { @@ -174,7 +175,7 @@ private void initializeLiquibase(boolean liquibaseEnabled) { initialTenantStoreLiquibase = mock(ExtendedSpringLiquibase.class); tenantStoreLiquibase = mock(ExtendedSpringLiquibase.class); - defaultTenantDataSource = mock(DataSource.class); + defaultTenantDataSource = mock(HikariDataSource.class); TenantPasswordEncryptionTask tenantPasswordEncryptor = mock(TenantPasswordEncryptionTask.class);