You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by ar...@apache.org on 2023/04/15 08:40:58 UTC

[fineract] branch develop updated: FINERACT-1913-Initializing-db-connection-pool-at-startup

This is an automated email from the ASF dual-hosted git repository.

arnold pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git


The following commit(s) were added to refs/heads/develop by this push:
     new c18e50683 FINERACT-1913-Initializing-db-connection-pool-at-startup
c18e50683 is described below

commit c18e5068320dd08c0d8860ccaef483cf9a045cd0
Author: Ruchi Dhamankar <ru...@gmail.com>
AuthorDate: Thu Apr 13 20:11:08 2023 +0530

    FINERACT-1913-Initializing-db-connection-pool-at-startup
---
 .../TomcatJdbcDataSourcePerTenantService.java      | 62 ++++++++++++++++------
 1 file changed, 47 insertions(+), 15 deletions(-)

diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/database/TomcatJdbcDataSourcePerTenantService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/database/TomcatJdbcDataSourcePerTenantService.java
index b01d6999d..fb829d664 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/database/TomcatJdbcDataSourcePerTenantService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/database/TomcatJdbcDataSourcePerTenantService.java
@@ -18,14 +18,21 @@
  */
 package org.apache.fineract.infrastructure.core.service.database;
 
-import java.util.HashMap;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import javax.sql.DataSource;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
 import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection;
 import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
+import org.apache.fineract.infrastructure.core.service.tenant.TenantDetailsService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextRefreshedEvent;
 import org.springframework.stereotype.Service;
 
 /**
@@ -34,19 +41,22 @@ import org.springframework.stereotype.Service;
  *
  * {@link ThreadLocalContextUtil} is used to retrieve the {@link FineractPlatformTenant} for the request.
  */
+@Slf4j
 @Service
-public class TomcatJdbcDataSourcePerTenantService implements RoutingDataSourceService {
+public class TomcatJdbcDataSourcePerTenantService implements RoutingDataSourceService, ApplicationListener<ContextRefreshedEvent> {
 
-    private static final Map<Long, DataSource> TENANT_TO_DATA_SOURCE_MAP = new HashMap<>(1);
+    private static final Map<Long, DataSource> TENANT_TO_DATA_SOURCE_MAP = new ConcurrentHashMap<>();
     private final DataSource tenantDataSource;
+    private final TenantDetailsService tenantDetailsService;
 
     private final DataSourcePerTenantServiceFactory dataSourcePerTenantServiceFactory;
 
     @Autowired
     public TomcatJdbcDataSourcePerTenantService(final @Qualifier("hikariTenantDataSource") DataSource tenantDataSource,
-            final DataSourcePerTenantServiceFactory dataSourcePerTenantServiceFactory) {
+            final DataSourcePerTenantServiceFactory dataSourcePerTenantServiceFactory, final TenantDetailsService tenantDetailsService) {
         this.tenantDataSource = tenantDataSource;
         this.dataSourcePerTenantServiceFactory = dataSourcePerTenantServiceFactory;
+        this.tenantDetailsService = tenantDetailsService;
     }
 
     @Override
@@ -57,20 +67,42 @@ public class TomcatJdbcDataSourcePerTenantService implements RoutingDataSourceSe
         final FineractPlatformTenant tenant = ThreadLocalContextUtil.getTenant();
         if (tenant != null) {
             final FineractPlatformTenantConnection tenantConnection = tenant.getConnection();
+            Long tenantConnectionKey = tenantConnection.getConnectionId();
+            // if tenantConnection information available switch to the
+            // appropriate datasource for that tenant.
+            actualDataSource = TENANT_TO_DATA_SOURCE_MAP.computeIfAbsent(tenantConnectionKey, (key) -> {
+                DataSource tenantSpecificDataSource = dataSourcePerTenantServiceFactory.createNewDataSourceFor(tenantConnection);
+                return tenantSpecificDataSource;
+            });
 
-            synchronized (TENANT_TO_DATA_SOURCE_MAP) {
-                // if tenantConnection information available switch to the
-                // appropriate datasource for that tenant.
-                DataSource possibleDS = TENANT_TO_DATA_SOURCE_MAP.get(tenantConnection.getConnectionId());
-                if (possibleDS != null) {
-                    actualDataSource = possibleDS;
-                } else {
-                    actualDataSource = dataSourcePerTenantServiceFactory.createNewDataSourceFor(tenantConnection);
-                    TENANT_TO_DATA_SOURCE_MAP.put(tenantConnection.getConnectionId(), actualDataSource);
-                }
-            }
         }
 
         return actualDataSource;
     }
+
+    @Override
+    public void onApplicationEvent(ContextRefreshedEvent event) {
+        final List<FineractPlatformTenant> allTenants = tenantDetailsService.findAllTenants();
+        for (final FineractPlatformTenant tenant : allTenants) {
+            initializeDataSourceConnection(tenant);
+        }
+    }
+
+    private void initializeDataSourceConnection(FineractPlatformTenant tenant) {
+        log.debug("Initializing database connection for {}", tenant.getName());
+        final FineractPlatformTenantConnection tenantConnection = tenant.getConnection();
+        Long tenantConnectionKey = tenantConnection.getConnectionId();
+        TENANT_TO_DATA_SOURCE_MAP.computeIfAbsent(tenantConnectionKey, (key) -> {
+            DataSource tenantSpecificDataSource = dataSourcePerTenantServiceFactory.createNewDataSourceFor(tenantConnection);
+            try (Connection connection = tenantSpecificDataSource.getConnection()) {
+                String url = connection.getMetaData().getURL();
+                log.debug("Established database connection with URL {}", url);
+            } catch (SQLException e) {
+                log.error("Error while initializing database connection for {}", tenant.getName(), e);
+            }
+            return tenantSpecificDataSource;
+        });
+        log.debug("Database connection for {} initialized", tenant.getName());
+
+    }
 }