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

yasith pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airavata.git


The following commit(s) were added to refs/heads/master by this push:
     new dbb1ec5756 reliability: consolidate monitoring, migrate JDBC, fix JPA, 
harden startup/shutdown (#603)
dbb1ec5756 is described below

commit dbb1ec5756e4adbaa86c740f3594ef5a8d2afa74
Author: Yasith Jayawardana <[email protected]>
AuthorDate: Mon Mar 30 14:23:37 2026 -0400

    reliability: consolidate monitoring, migrate JDBC, fix JPA, harden 
startup/shutdown (#603)
    
    Consolidate 4 redundant MonitoringServer instances into unified :9097. 
Bridge Spring datasource into legacy JDBC config (single source of truth). 
Switch to Spring Boot auto-configured JPA with @EntityScan + 
PhysicalNamingStrategyStandardImpl. Replace wurstmeister/kafka with 
apache/kafka:3.9.0 (KRaft). Add compose healthchecks, graceful shutdown, 
HikariCP resilience, infrastructure health indicator.
---
 .../common/config/ApplicationSettings.java         | 12 +++-
 .../airavata/common/db/SpringSettingsBridge.java   | 48 +++++++++++++++
 .../airavata/credential/model/Credential.java      |  1 -
 .../repository/CredentialReaderImpl.java           |  3 +-
 .../credential/repository/db/CommunityUserDAO.java |  4 +-
 .../execution/orchestrator/GlobalParticipant.java  | 11 ----
 .../orchestrator/ParserWorkflowManager.java        | 10 ---
 .../orchestrator/PostWorkflowManager.java          | 10 ---
 .../execution/orchestrator/PreWorkflowManager.java | 10 ---
 .../src/main/resources/airavata-server.properties  | 20 ------
 .../src/test/resources/airavata-server.properties  | 11 ----
 .../apache/airavata/server/AiravataServerMain.java | 36 +----------
 .../health/InfrastructureHealthIndicator.java      | 72 ++++++++++++++++++++++
 airavata-server/src/main/resources/application.yml | 18 +++++-
 .../thrift/handler/AiravataServerHandler.java      |  1 +
 .../thrift/handler/OrchestratorServerHandler.java  |  3 +-
 compose.yml                                        | 50 ++++++++++++---
 .../inventories/dev/group_vars/all/vars.yml        |  3 -
 .../inventories/staging/group_vars/all/vars.yml    |  3 -
 .../roles/airavata_services/defaults/main.yml      | 16 -----
 .../templates/airavata-server.properties.j2        | 21 -------
 .../templates/airavata-server.properties.j2        |  9 ---
 .../templates/airavata-server.properties.j2        |  9 ---
 .../deployment-scripts/airavata-server.properties  |  9 ---
 scripts/setup.sh                                   | 26 ++++----
 25 files changed, 209 insertions(+), 207 deletions(-)

diff --git 
a/airavata-api/src/main/java/org/apache/airavata/common/config/ApplicationSettings.java
 
b/airavata-api/src/main/java/org/apache/airavata/common/config/ApplicationSettings.java
index 892c5627d7..2cf9d7d20c 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/common/config/ApplicationSettings.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/common/config/ApplicationSettings.java
@@ -26,6 +26,7 @@ import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.regex.Pattern;
 import org.apache.airavata.common.exception.ApplicationSettingsException;
 import org.apache.airavata.common.util.StringUtil;
@@ -39,6 +40,8 @@ public class ApplicationSettings {
 
     public static String ADDITIONAL_SETTINGS_FILES = "external.settings";
 
+    private static final Map<String, String> overrides = new 
ConcurrentHashMap<>();
+
     protected Properties properties = new Properties();
 
     private Exception propertyLoadException;
@@ -132,7 +135,10 @@ public class ApplicationSettings {
 
     public String getSettingImpl(String key) throws 
ApplicationSettingsException {
         String rawValue;
-        if (System.getProperties().containsKey(key)) {
+        if (overrides.containsKey(key)) {
+            rawValue = overrides.get(key);
+
+        } else if (System.getProperties().containsKey(key)) {
             rawValue = System.getProperties().getProperty(key);
 
         } else if (System.getenv().containsKey(key)) {
@@ -207,6 +213,10 @@ public class ApplicationSettings {
         return getInstance().getSettingImpl(key, defaultValue);
     }
 
+    public static void setOverride(String key, String value) {
+        overrides.put(key, value);
+    }
+
     public static void setSetting(String key, String value) throws 
ApplicationSettingsException {
         getInstance().properties.setProperty(key, value);
         getInstance().saveProperties();
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/common/db/SpringSettingsBridge.java
 
b/airavata-api/src/main/java/org/apache/airavata/common/db/SpringSettingsBridge.java
new file mode 100644
index 0000000000..e2d36389e7
--- /dev/null
+++ 
b/airavata-api/src/main/java/org/apache/airavata/common/db/SpringSettingsBridge.java
@@ -0,0 +1,48 @@
+/**
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+package org.apache.airavata.common.db;
+
+import org.apache.airavata.common.config.ApplicationSettings;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+/**
+ * Bridges Spring datasource configuration into {@link ApplicationSettings} so 
that legacy code
+ * reading {@code airavata.jdbc.*} transparently receives the same values as
+ * {@code spring.datasource.*}. Runs in the constructor (not @PostConstruct) 
to ensure values
+ * are available before any other bean reads them.
+ */
+@Component
+@Order(Ordered.HIGHEST_PRECEDENCE)
+public class SpringSettingsBridge {
+
+    public SpringSettingsBridge(
+            @Value("${spring.datasource.url}") String url,
+            @Value("${spring.datasource.username}") String username,
+            @Value("${spring.datasource.password}") String password,
+            @Value("${spring.datasource.driver-class-name}") String 
driverClassName) {
+        ApplicationSettings.setOverride("airavata.jdbc.url", url);
+        ApplicationSettings.setOverride("airavata.jdbc.user", username);
+        ApplicationSettings.setOverride("airavata.jdbc.password", password);
+        ApplicationSettings.setOverride("airavata.jdbc.driver", 
driverClassName);
+    }
+}
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/model/Credential.java
 
b/airavata-api/src/main/java/org/apache/airavata/credential/model/Credential.java
index eaf90a008d..6df05ca306 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/credential/model/Credential.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/credential/model/Credential.java
@@ -67,5 +67,4 @@ public abstract class Credential implements Serializable {
     public Date getCertificateRequestedTime() {
         return persistedTime;
     }
-
 }
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/repository/CredentialReaderImpl.java
 
b/airavata-api/src/main/java/org/apache/airavata/credential/repository/CredentialReaderImpl.java
index 3fded1754d..048b4c5328 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/credential/repository/CredentialReaderImpl.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/credential/repository/CredentialReaderImpl.java
@@ -157,8 +157,7 @@ public class CredentialReaderImpl implements 
CredentialReader, Serializable {
     }
 
     public void updateCommunityUserEmail(String gatewayName, String 
communityUser, String email)
-            throws CredentialStoreException {
-    }
+            throws CredentialStoreException {}
 
     public void removeCredentials(String gatewayName, String tokenId) throws 
CredentialStoreException {
 
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/credential/repository/db/CommunityUserDAO.java
 
b/airavata-api/src/main/java/org/apache/airavata/credential/repository/db/CommunityUserDAO.java
index c69ddd0bd5..083eeb65a1 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/credential/repository/db/CommunityUserDAO.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/credential/repository/db/CommunityUserDAO.java
@@ -133,9 +133,7 @@ public class CommunityUserDAO extends ParentDAO {
         }
     }
 
-    public void updateCommunityUser(CommunityUser user) throws 
CredentialStoreException {
-
-    }
+    public void updateCommunityUser(CommunityUser user) throws 
CredentialStoreException {}
 
     public CommunityUser getCommunityUser(String gatewayName, String 
communityUserName, Connection connection)
             throws CredentialStoreException {
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/GlobalParticipant.java
 
b/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/GlobalParticipant.java
index 59871fa4ed..0bf3d79baa 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/GlobalParticipant.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/GlobalParticipant.java
@@ -21,10 +21,8 @@ package org.apache.airavata.execution.orchestrator;
 
 import java.util.ArrayList;
 import java.util.List;
-import org.apache.airavata.common.config.ServerSettings;
 import org.apache.airavata.common.exception.ApplicationSettingsException;
 import org.apache.airavata.common.server.IServer;
-import org.apache.airavata.common.server.MonitoringServer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -95,15 +93,6 @@ public class GlobalParticipant extends 
HelixParticipant<AbstractTask> implements
                 
taskClasses.add(Class.forName(taskClassName).asSubclass(AbstractTask.class));
             }
 
-            if 
(ServerSettings.getBooleanSetting("participant.monitoring.enabled")) {
-                MonitoringServer monitoringServer = new MonitoringServer(
-                        
ServerSettings.getSetting("participant.monitoring.host"),
-                        
ServerSettings.getIntSetting("participant.monitoring.port"));
-                new Thread(monitoringServer, "monitoring-server").start();
-
-                Runtime.getRuntime().addShutdownHook(new 
Thread(monitoringServer::stop));
-            }
-
             GlobalParticipant participant = new GlobalParticipant(taskClasses, 
null);
             participant.run();
 
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/ParserWorkflowManager.java
 
b/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/ParserWorkflowManager.java
index 749881239f..7a14f563bf 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/ParserWorkflowManager.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/ParserWorkflowManager.java
@@ -24,7 +24,6 @@ import org.apache.airavata.common.config.ServerSettings;
 import org.apache.airavata.common.exception.ApplicationSettingsException;
 import org.apache.airavata.common.server.CountMonitor;
 import org.apache.airavata.common.server.IServer;
-import org.apache.airavata.common.server.MonitoringServer;
 import org.apache.airavata.execution.task.*;
 import org.apache.airavata.execution.task.ParsingTaskInput;
 import org.apache.airavata.execution.task.ParsingTaskInputs;
@@ -67,15 +66,6 @@ public class ParserWorkflowManager implements IServer {
 
     public static void main(String[] args) throws Exception {
 
-        if 
(ServerSettings.getBooleanSetting("parser.workflow.manager.monitoring.enabled"))
 {
-            MonitoringServer monitoringServer = new MonitoringServer(
-                    
ServerSettings.getSetting("parser.workflow.manager.monitoring.host"),
-                    
ServerSettings.getIntSetting("parser.workflow.manager.monitoring.port"));
-            new Thread(monitoringServer, "monitoring-server").start();
-
-            Runtime.getRuntime().addShutdownHook(new 
Thread(monitoringServer::stop));
-        }
-
         ParserWorkflowManager manager = new ParserWorkflowManager();
         manager.run();
     }
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/PostWorkflowManager.java
 
b/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/PostWorkflowManager.java
index 8fbdd24c95..f0ddd9af1f 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/PostWorkflowManager.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/PostWorkflowManager.java
@@ -25,7 +25,6 @@ import org.apache.airavata.common.config.ServerSettings;
 import org.apache.airavata.common.exception.ApplicationSettingsException;
 import org.apache.airavata.common.server.CountMonitor;
 import org.apache.airavata.common.server.IServer;
-import org.apache.airavata.common.server.MonitoringServer;
 import org.apache.airavata.common.util.AiravataUtils;
 import org.apache.airavata.common.util.ThriftUtils;
 import org.apache.airavata.execution.monitor.JobStateValidator;
@@ -69,15 +68,6 @@ public class PostWorkflowManager implements IServer {
 
     public static void main(String[] args) throws Exception {
 
-        if 
(ServerSettings.getBooleanSetting("post.workflow.manager.monitoring.enabled")) {
-            MonitoringServer monitoringServer = new MonitoringServer(
-                    
ServerSettings.getSetting("post.workflow.manager.monitoring.host"),
-                    
ServerSettings.getIntSetting("post.workflow.manager.monitoring.port"));
-            new Thread(monitoringServer, "monitoring-server").start();
-
-            Runtime.getRuntime().addShutdownHook(new 
Thread(monitoringServer::stop));
-        }
-
         PostWorkflowManager postManager = new PostWorkflowManager();
         postManager.run();
     }
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/PreWorkflowManager.java
 
b/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/PreWorkflowManager.java
index 5dccbc63fd..d11c1560a6 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/PreWorkflowManager.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/execution/orchestrator/PreWorkflowManager.java
@@ -30,7 +30,6 @@ import org.apache.airavata.common.exception.AiravataException;
 import org.apache.airavata.common.exception.ApplicationSettingsException;
 import org.apache.airavata.common.server.CountMonitor;
 import org.apache.airavata.common.server.IServer;
-import org.apache.airavata.common.server.MonitoringServer;
 import org.apache.airavata.common.util.ThriftUtils;
 import org.apache.airavata.execution.task.CancelCompletingTask;
 import org.apache.airavata.execution.task.CompletingTask;
@@ -314,15 +313,6 @@ public class PreWorkflowManager implements IServer {
 
     public static void main(String[] args) throws Exception {
 
-        if 
(ServerSettings.getBooleanSetting("pre.workflow.manager.monitoring.enabled")) {
-            MonitoringServer monitoringServer = new MonitoringServer(
-                    
ServerSettings.getSetting("pre.workflow.manager.monitoring.host"),
-                    
ServerSettings.getIntSetting("pre.workflow.manager.monitoring.port"));
-            new Thread(monitoringServer, "monitoring-server").start();
-
-            Runtime.getRuntime().addShutdownHook(new 
Thread(monitoringServer::stop));
-        }
-
         PreWorkflowManager preWorkflowManager = new PreWorkflowManager();
         preWorkflowManager.run();
     }
diff --git a/airavata-api/src/main/resources/airavata-server.properties 
b/airavata-api/src/main/resources/airavata-server.properties
index 956e307386..5f63fe8f4c 100644
--- a/airavata-api/src/main/resources/airavata-server.properties
+++ b/airavata-api/src/main/resources/airavata-server.properties
@@ -32,13 +32,6 @@ credential.store.server.port=8930
 profile.service.server.host=localhost
 profile.service.server.port=8930
 
-# Database Configuration
-airavata.jdbc.driver=org.mariadb.jdbc.Driver
-airavata.jdbc.url=jdbc:mariadb://localhost:13306/airavata
-airavata.jdbc.user=airavata
-airavata.jdbc.password=123456
-airavata.jdbc.validationQuery=SELECT 1
-
 cluster.status.monitoring.enable=false
 cluster.status.monitoring.repeat.time=18000
 
@@ -47,9 +40,6 @@ data.analyzer.job.scanning.enable=false
 data.parser.delete.container=true
 data.parser.broker.publisher.id=ParsingPublisher
 parser.workflow.manager.name=ParserWorkflowManager
-parser.workflow.manager.monitoring.enabled=false
-parser.workflow.manager.monitoring.host=localhost
-parser.workflow.manager.monitoring.port=9095
 
 default.registry.gateway=default
 default.registry.oauth.client.id=pga
@@ -108,20 +98,10 @@ metaschedluer.job.scanning.enable=false
 
 data.parser.storage.resource.id=CHANGE_ME
 
-participant.monitoring.enabled=true
-participant.monitoring.host=localhost
-participant.monitoring.port=9096
-
 post.workflow.manager.loadbalance.clusters=false
-post.workflow.manager.monitoring.enabled=true
-post.workflow.manager.monitoring.host=localhost
-post.workflow.manager.monitoring.port=9094
 post.workflow.manager.name=AiravataPostWM
 
 pre.workflow.manager.loadbalance.clusters=false
-pre.workflow.manager.monitoring.enabled=true
-pre.workflow.manager.monitoring.host=localhost
-pre.workflow.manager.monitoring.port=9093
 pre.workflow.manager.name=AiravataPreWM
 
 
diff --git a/airavata-api/src/test/resources/airavata-server.properties 
b/airavata-api/src/test/resources/airavata-server.properties
index 0c00542576..929b73a644 100644
--- a/airavata-api/src/test/resources/airavata-server.properties
+++ b/airavata-api/src/test/resources/airavata-server.properties
@@ -24,17 +24,6 @@
 #
 ###########################################################################
 
-###########################################################################
-#  Unified Database Configuration
-###########################################################################
-
-# Unified JDBC configuration for all catalogs
-airavata.jdbc.driver=org.mariadb.jdbc.Driver
-airavata.jdbc.url=jdbc:mariadb://localhost:3306/airavata
-airavata.jdbc.user=airavata
-airavata.jdbc.password=airavata
-airavata.jdbc.validationQuery=SELECT 1
-
 # Properties for default user mode
 default.registry.user=admin
 default.registry.gateway=php_reference_gateway
diff --git 
a/airavata-server/src/main/java/org/apache/airavata/server/AiravataServerMain.java
 
b/airavata-server/src/main/java/org/apache/airavata/server/AiravataServerMain.java
index 11d7bdcfe8..509a7159b5 100644
--- 
a/airavata-server/src/main/java/org/apache/airavata/server/AiravataServerMain.java
+++ 
b/airavata-server/src/main/java/org/apache/airavata/server/AiravataServerMain.java
@@ -19,52 +19,22 @@
 */
 package org.apache.airavata.server;
 
-import javax.sql.DataSource;
-
 import org.apache.airavata.common.config.AiravataServerProperties;
 import org.apache.airavata.server.grpc.AiravataGrpcServerConfig;
 import org.apache.airavata.server.rest.AiravataRestServerConfig;
 import org.apache.airavata.server.thrift.AiravataThriftServerConfig;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
-import 
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
+import org.springframework.boot.autoconfigure.domain.EntityScan;
 import 
org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Import;
-import org.springframework.orm.jpa.JpaTransactionManager;
-import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
-import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
-import org.springframework.transaction.PlatformTransactionManager;
-
-import jakarta.persistence.EntityManagerFactory;
 
-@SpringBootApplication(
-    scanBasePackages = {"org.apache.airavata.server", 
"org.apache.airavata.common.db"},
-    exclude = {HibernateJpaAutoConfiguration.class}
-)
+@SpringBootApplication(scanBasePackages = {"org.apache.airavata.server", 
"org.apache.airavata.common.db"})
+@EntityScan("org.apache.airavata")
 @EnableConfigurationProperties(AiravataServerProperties.class)
 @Import({AiravataRestServerConfig.class, AiravataGrpcServerConfig.class, 
AiravataThriftServerConfig.class})
 public class AiravataServerMain {
     public static void main(String[] args) {
         SpringApplication.run(AiravataServerMain.class, args);
     }
-
-    @Bean
-    public LocalContainerEntityManagerFactoryBean 
entityManagerFactory(DataSource dataSource) {
-        var em = new LocalContainerEntityManagerFactoryBean();
-        em.setDataSource(dataSource);
-        // Scan all entity packages instead of using persistence.xml
-        em.setPackagesToScan("org.apache.airavata");
-        em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
-        em.getJpaPropertyMap().put("hibernate.hbm2ddl.auto", "none");
-        em.getJpaPropertyMap().put("hibernate.enable_lazy_load_no_trans", 
"true");
-        em.getJpaPropertyMap().put("hibernate.physical_naming_strategy",
-            
"org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl");
-        return em;
-    }
-
-    @Bean
-    public PlatformTransactionManager transactionManager(EntityManagerFactory 
emf) {
-        return new JpaTransactionManager(emf);
-    }
 }
diff --git 
a/airavata-server/src/main/java/org/apache/airavata/server/health/InfrastructureHealthIndicator.java
 
b/airavata-server/src/main/java/org/apache/airavata/server/health/InfrastructureHealthIndicator.java
new file mode 100644
index 0000000000..604db1907d
--- /dev/null
+++ 
b/airavata-server/src/main/java/org/apache/airavata/server/health/InfrastructureHealthIndicator.java
@@ -0,0 +1,72 @@
+/**
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+package org.apache.airavata.server.health;
+
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import org.apache.airavata.common.config.ServerSettings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.actuate.health.Health;
+import org.springframework.boot.actuate.health.HealthIndicator;
+import org.springframework.stereotype.Component;
+
+/**
+ * Actuator health indicator that checks TCP connectivity to RabbitMQ, Kafka, 
and ZooKeeper.
+ * Reports DOWN if any required infrastructure service is unreachable.
+ */
+@Component("infrastructure")
+public class InfrastructureHealthIndicator implements HealthIndicator {
+
+    private static final Logger logger = 
LoggerFactory.getLogger(InfrastructureHealthIndicator.class);
+    private static final int CONNECT_TIMEOUT_MS = 3000;
+
+    @Override
+    public Health health() {
+        var builder = Health.up();
+        boolean allHealthy = true;
+
+        allHealthy &= checkTcp(builder, "rabbitmq", "localhost", 5672);
+        allHealthy &= checkTcp(builder, "zookeeper", "localhost", 2181);
+
+        try {
+            String kafkaUrl = ServerSettings.getSetting("kafka.broker.url", 
"localhost:9092");
+            String[] parts = kafkaUrl.split(":");
+            allHealthy &= checkTcp(builder, "kafka", parts[0], 
Integer.parseInt(parts[1]));
+        } catch (Exception e) {
+            builder.withDetail("kafka", "config error: " + e.getMessage());
+            allHealthy = false;
+        }
+
+        return allHealthy ? builder.build() : builder.down().build();
+    }
+
+    private boolean checkTcp(Health.Builder builder, String name, String host, 
int port) {
+        try (Socket socket = new Socket()) {
+            socket.connect(new InetSocketAddress(host, port), 
CONNECT_TIMEOUT_MS);
+            builder.withDetail(name, "reachable");
+            return true;
+        } catch (Exception e) {
+            logger.warn("{} health check failed: {}:{} - {}", name, host, 
port, e.getMessage());
+            builder.withDetail(name, "unreachable: " + e.getMessage());
+            return false;
+        }
+    }
+}
diff --git a/airavata-server/src/main/resources/application.yml 
b/airavata-server/src/main/resources/application.yml
index 57f4b02c6e..6b66386a96 100644
--- a/airavata-server/src/main/resources/application.yml
+++ b/airavata-server/src/main/resources/application.yml
@@ -12,19 +12,32 @@ spring:
     driver-class-name: org.mariadb.jdbc.Driver
     hikari:
       pool-name: AiravataPool
+      connection-timeout: 30000
+      initialization-fail-timeout: -1
+      minimum-idle: 2
+      maximum-pool-size: 20
       leak-detection-threshold: 20000
   jpa:
     hibernate:
       ddl-auto: none
+      naming:
+        physical-strategy: 
org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
     open-in-view: false
+    properties:
+      hibernate:
+        enable_lazy_load_no_trans: true
   servlet:
     multipart:
       max-file-size: 200MB
       max-request-size: 200MB
 
-# REST server port (also serves Swagger UI)
+# REST server
 server:
   port: 18889
+  shutdown: graceful
+
+spring.lifecycle:
+  timeout-per-shutdown-phase: 30s
 
 springdoc:
   api-docs:
@@ -45,6 +58,9 @@ management:
     web:
       exposure:
         include: health,info
+  endpoint:
+    health:
+      show-details: always
 
 airavata.security:
   openid-url: http://localhost:18080/realms/default
diff --git 
a/airavata-server/thrift/src/main/java/org/apache/airavata/server/thrift/handler/AiravataServerHandler.java
 
b/airavata-server/thrift/src/main/java/org/apache/airavata/server/thrift/handler/AiravataServerHandler.java
index 02a7b3bb55..2854ec67c1 100644
--- 
a/airavata-server/thrift/src/main/java/org/apache/airavata/server/thrift/handler/AiravataServerHandler.java
+++ 
b/airavata-server/thrift/src/main/java/org/apache/airavata/server/thrift/handler/AiravataServerHandler.java
@@ -97,6 +97,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Component;
 
 @Component
[email protected]("springSettingsBridge")
 public class AiravataServerHandler implements Airavata.Iface {
     private static final Logger logger = 
LoggerFactory.getLogger(AiravataServerHandler.class);
     private Publisher statusPublisher;
diff --git 
a/airavata-server/thrift/src/main/java/org/apache/airavata/server/thrift/handler/OrchestratorServerHandler.java
 
b/airavata-server/thrift/src/main/java/org/apache/airavata/server/thrift/handler/OrchestratorServerHandler.java
index 29def22402..e603752004 100644
--- 
a/airavata-server/thrift/src/main/java/org/apache/airavata/server/thrift/handler/OrchestratorServerHandler.java
+++ 
b/airavata-server/thrift/src/main/java/org/apache/airavata/server/thrift/handler/OrchestratorServerHandler.java
@@ -650,8 +650,7 @@ public class OrchestratorServerHandler implements 
OrchestratorService.Iface {
     }
 
     private void launchWorkflowExperiment(String experimentId, String 
airavataCredStoreToken, String gatewayId)
-            throws TException {
-    }
+            throws TException {}
 
     private class SingleAppExperimentRunner implements Runnable {
 
diff --git a/compose.yml b/compose.yml
index 31b88d9c13..e5fea5eeea 100644
--- a/compose.yml
+++ b/compose.yml
@@ -14,6 +14,12 @@ services:
       - 
./airavata-api/src/main/resources/conf/db/migration/airavata/V1__Baseline_schema.sql:/docker-entrypoint-initdb.d/01-schema.sql:ro
     ports:
       - "13306:3306"
+    healthcheck:
+      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
+      interval: 10s
+      timeout: 5s
+      retries: 5
+      start_period: 30s
 
   rabbitmq:
     image: rabbitmq:4.0-management
@@ -27,6 +33,12 @@ services:
     ports:
       - "5672:5672"
       - "15672:15672"
+    healthcheck:
+      test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"]
+      interval: 10s
+      timeout: 5s
+      retries: 5
+      start_period: 20s
 
   zookeeper:
     image: zookeeper:3.9
@@ -37,20 +49,37 @@ services:
       - zk_logs:/datalog
     ports:
       - "2181:2181"
+    healthcheck:
+      test: ["CMD-SHELL", "curl -sf http://localhost:8080/commands/ruok || 
exit 1"]
+      interval: 10s
+      timeout: 5s
+      retries: 5
+      start_period: 10s
 
   kafka:
-    image: wurstmeister/kafka:2.13-2.8.1
+    image: apache/kafka:3.9.0
     container_name: airavata-kafka
     restart: unless-stopped
     environment:
-      KAFKA_ADVERTISED_HOST_NAME: localhost
-      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
+      KAFKA_NODE_ID: 1
+      KAFKA_PROCESS_ROLES: broker,controller
+      KAFKA_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093
+      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
+      KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
+      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: 
CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT
+      KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka:9093
+      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
+      CLUSTER_ID: airavata-kafka-cluster-id-01
     volumes:
-      - kafka_data:/kafka
+      - kafka_data:/var/lib/kafka/data
     ports:
       - "9092:9092"
-    depends_on:
-      - zookeeper
+    healthcheck:
+      test: ["CMD-SHELL", "/opt/kafka/bin/kafka-broker-api-versions.sh 
--bootstrap-server localhost:9092 > /dev/null 2>&1"]
+      interval: 10s
+      timeout: 10s
+      retries: 5
+      start_period: 30s
 
   keycloak:
     image: keycloak/keycloak:25.0
@@ -65,6 +94,12 @@ services:
     command: ["start", "--import-realm"]
     ports:
       - "18080:18080"
+    healthcheck:
+      test: ["CMD-SHELL", "exec 3<>/dev/tcp/localhost/9000 && echo -e 'GET 
/health/ready HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n' 
>&3 && cat <&3 | grep -q '200 OK'"]
+      interval: 10s
+      timeout: 5s
+      retries: 10
+      start_period: 60s
 
   # Dev tools (start with: docker compose --profile tools up -d)
 
@@ -76,7 +111,8 @@ services:
     ports:
       - "18088:8080"
     depends_on:
-      - db
+      db:
+        condition: service_healthy
 
 volumes:
   db_data:
diff --git a/dev-tools/ansible/inventories/dev/group_vars/all/vars.yml 
b/dev-tools/ansible/inventories/dev/group_vars/all/vars.yml
index ce7dd0d8ed..5e3b1ed174 100644
--- a/dev-tools/ansible/inventories/dev/group_vars/all/vars.yml
+++ b/dev-tools/ansible/inventories/dev/group_vars/all/vars.yml
@@ -38,9 +38,6 @@ credential_store: "{{ db_name }}"
 profile_service: "{{ db_name }}"
 research_catalog: "{{ db_name }}"
 
-# Database driver (unified)
-airavata_jdbc_driver: "org.mariadb.jdbc.Driver"
-
 # Paths
 local_data_location: "/home/{{ deploy_user }}/temp-storage"
 file_server_storage_location: "/home/{{ deploy_user }}/temp-storage"
diff --git a/dev-tools/ansible/inventories/staging/group_vars/all/vars.yml 
b/dev-tools/ansible/inventories/staging/group_vars/all/vars.yml
index 1f7bf7f748..ff14cc6989 100644
--- a/dev-tools/ansible/inventories/staging/group_vars/all/vars.yml
+++ b/dev-tools/ansible/inventories/staging/group_vars/all/vars.yml
@@ -38,9 +38,6 @@ credential_store: "{{ db_name }}"
 profile_service: "{{ db_name }}"
 research_catalog: "{{ db_name }}"
 
-# Database driver (unified)
-airavata_jdbc_driver: "org.mariadb.jdbc.Driver"
-
 # Paths
 local_data_location: "/home/{{ deploy_user }}/temp-storage"
 file_server_storage_location: "/home/{{ deploy_user }}/temp-storage"
diff --git a/dev-tools/ansible/roles/airavata_services/defaults/main.yml 
b/dev-tools/ansible/roles/airavata_services/defaults/main.yml
index 1f0ac4ea01..ef086c7b83 100644
--- a/dev-tools/ansible/roles/airavata_services/defaults/main.yml
+++ b/dev-tools/ansible/roles/airavata_services/defaults/main.yml
@@ -37,16 +37,6 @@ monitoring_port: 9097
 # Service hosts
 api_server_host: "airavata.localhost"
 
-# Monitoring hosts
-participant_monitoring_host: "airavata.localhost"
-pre_workflow_manager_monitoring_host: "airavata.localhost"
-post_workflow_manager_monitoring_host: "airavata.localhost"
-
-# Monitoring ports (workflow managers)
-participant_monitoring_port: 9096
-pre_wm_monitoring_port: 9093
-post_wm_monitoring_port: 9094
-
 # All services run on Airavata server (no separate server hosts needed)
 
 # Airavata Server (replaces separate service configurations)
@@ -59,9 +49,6 @@ default_registry_gateway: "default"
 default_registry_oauth_client_id: "pga"
 super_tenant_gatewayId: "default"
 
-# JDBC driver (unified)
-airavata_jdbc_driver: "org.mariadb.jdbc.Driver"
-
 # Security configuration
 security_manager_class: 
"org.apache.airavata.security.service.KeyCloakSecurityManager"
 TLS_enabled: false
@@ -95,7 +82,6 @@ embedded_zk: false
 helix_cluster_name: "AiravataCluster"
 helix_controller_name: "AiravataController"
 helix_participant_name: "AiravataParticipant"
-participant_monitoring_enabled: true
 
 # Job monitor configuration
 enable_realtime_monitor: true
@@ -119,12 +105,10 @@ archive_logs_on_stop: true
 
 # Pre-workflow manager configuration
 pre_workflow_manager_loadbalance_clusters: false
-pre_workflow_manager_monitoring_enabled: true
 pre_workflow_manager_name: "AiravataPreWM"
 
 # Post-workflow manager configuration
 post_workflow_manager_loadbalance_clusters: false
-post_workflow_manager_monitoring_enabled: true
 post_workflow_manager_name: "AiravataPostWM"
 
 # Parser-workflow configuration
diff --git 
a/dev-tools/ansible/roles/airavata_services/templates/airavata-server.properties.j2
 
b/dev-tools/ansible/roles/airavata_services/templates/airavata-server.properties.j2
index b5a59fb4ab..ed3eca9750 100644
--- 
a/dev-tools/ansible/roles/airavata_services/templates/airavata-server.properties.j2
+++ 
b/dev-tools/ansible/roles/airavata_services/templates/airavata-server.properties.j2
@@ -24,15 +24,6 @@
 #
 ###########################################################################
 
-###########################################################################
-# Database Configuration
-###########################################################################
-airavata.jdbc.driver={{ airavata_jdbc_driver | 
default('org.mariadb.jdbc.Driver') }}
-airavata.jdbc.url={{ airavata_jdbc_url }}
-airavata.jdbc.user={{ airavata_jdbc_user }}
-airavata.jdbc.password={{ airavata_jdbc_password }}
-airavata.jdbc.validationQuery=SELECT 1
-
 ###########################################################################
 #  Generic Server Configurations
 ###########################################################################
@@ -118,9 +109,6 @@ iam.server.super.admin.password={{ iam_admin_password }}
 helix.cluster.name={{ helix_cluster_name }}
 helix.controller.name={{ helix_controller_name }}
 helix.participant.name={{ helix_participant_name }}
-participant.monitoring.enabled={{ participant_monitoring_enabled }}
-participant.monitoring.host={{ participant_monitoring_host }}
-participant.monitoring.port={{ participant_monitoring_port }}
 
 ###########################################################################
 # Job Monitor related properties
@@ -157,23 +145,14 @@ thrift.client.pool.abandoned.removal.logged={{ 
thrift_client_pool_abandoned_remo
 # Pre-workflow Configuration
 ###########################################################################
 pre.workflow.manager.loadbalance.clusters={{ 
pre_workflow_manager_loadbalance_clusters }}
-pre.workflow.manager.monitoring.enabled={{ 
pre_workflow_manager_monitoring_enabled }}
-pre.workflow.manager.monitoring.host={{ pre_workflow_manager_monitoring_host }}
-pre.workflow.manager.monitoring.port={{ pre_wm_monitoring_port }}
 pre.workflow.manager.name={{ pre_workflow_manager_name }}
 
 ###########################################################################
 # Post-workflow Configuration
 ###########################################################################
 post.workflow.manager.loadbalance.clusters={{ 
post_workflow_manager_loadbalance_clusters }}
-post.workflow.manager.monitoring.enabled={{ 
post_workflow_manager_monitoring_enabled }}
-post.workflow.manager.monitoring.host={{ post_workflow_manager_monitoring_host 
}}
-post.workflow.manager.monitoring.port={{ post_wm_monitoring_port }}
 post.workflow.manager.name={{ post_workflow_manager_name }}
 parser.workflow.manager.name={{ parser_workflow_manager_name | 
default('ParserWorkflowManager') }}
-parser.workflow.manager.monitoring.enabled={{ 
parser_workflow_manager_monitoring_enabled | default('false') }}
-parser.workflow.manager.monitoring.host={{ 
parser_workflow_manager_monitoring_host | default('localhost') }}
-parser.workflow.manager.monitoring.port={{ 
parser_workflow_manager_monitoring_port | default('9095') }}
 
 ###########################################################################
 # Parser-workflow Configuration
diff --git 
a/dev-tools/ansible/roles/api-orch/templates/airavata-server.properties.j2 
b/dev-tools/ansible/roles/api-orch/templates/airavata-server.properties.j2
index 989558674e..a1d67e847e 100644
--- a/dev-tools/ansible/roles/api-orch/templates/airavata-server.properties.j2
+++ b/dev-tools/ansible/roles/api-orch/templates/airavata-server.properties.j2
@@ -25,15 +25,6 @@
 #
 ###########################################################################
 
-###########################################################################
-# Database Configuration
-###########################################################################
-airavata.jdbc.driver={{ airavata_jdbc_driver | 
default('org.mariadb.jdbc.Driver') }}
-airavata.jdbc.url={{ airavata_jdbc_url }}
-airavata.jdbc.user={{ airavata_jdbc_user }}
-airavata.jdbc.password={{ airavata_jdbc_password }}
-airavata.jdbc.validationQuery=SELECT 1
-
 enable.sharing={{enable_sharing}}
 
 # Properties for default user mode
diff --git 
a/dev-tools/ansible/roles/registry/templates/airavata-server.properties.j2 
b/dev-tools/ansible/roles/registry/templates/airavata-server.properties.j2
index 3ddefd25fd..64dab9aed2 100644
--- a/dev-tools/ansible/roles/registry/templates/airavata-server.properties.j2
+++ b/dev-tools/ansible/roles/registry/templates/airavata-server.properties.j2
@@ -25,15 +25,6 @@
 #
 ###########################################################################
 
-###########################################################################
-# Database Configuration
-###########################################################################
-airavata.jdbc.driver={{ airavata_jdbc_driver | 
default('org.mariadb.jdbc.Driver') }}
-airavata.jdbc.url={{ airavata_jdbc_url }}
-airavata.jdbc.user={{ airavata_jdbc_user }}
-airavata.jdbc.password={{ airavata_jdbc_password }}
-airavata.jdbc.validationQuery=SELECT 1
-
 enable.sharing={{enable_sharing}}
 
 # Properties for default user mode
diff --git a/dev-tools/deployment-scripts/airavata-server.properties 
b/dev-tools/deployment-scripts/airavata-server.properties
index ef74232812..ca18ec5273 100644
--- a/dev-tools/deployment-scripts/airavata-server.properties
+++ b/dev-tools/deployment-scripts/airavata-server.properties
@@ -22,15 +22,6 @@
 # This file provides working defaults for Docker development environment
 ############################
 
-############################
-# Database Configuration
-############################
-airavata.jdbc.driver=org.mariadb.jdbc.Driver
-airavata.jdbc.url=jdbc:mariadb://mysql:3306/airavata
-airavata.jdbc.user=airavata
-airavata.jdbc.password=123456
-airavata.jdbc.validationQuery=SELECT 1
-
 ############################
 # AMQP (RabbitMQ) Configuration
 ############################
diff --git a/scripts/setup.sh b/scripts/setup.sh
index 660fd01396..e5f66a6851 100755
--- a/scripts/setup.sh
+++ b/scripts/setup.sh
@@ -10,22 +10,18 @@ echo "=== Airavata Setup ==="
 echo "Starting infrastructure services..."
 cd "$ROOT_DIR"
 docker compose up -d
-echo "Waiting for services to be ready..."
-sleep 10
-
-# Verify DB is up
-until docker exec airavata-db mariadb -h127.0.0.1 -uairavata -p123456 -e 
"SELECT 1" > /dev/null 2>&1; do
-    echo "  Waiting for MariaDB..."
-    sleep 2
-done
-echo "  MariaDB: ready"
-
-# Verify RabbitMQ is up
-until docker exec airavata-rabbitmq rabbitmqctl status > /dev/null 2>&1; do
-    echo "  Waiting for RabbitMQ..."
-    sleep 2
+echo "Waiting for services to be healthy..."
+
+# Wait for all compose healthchecks to pass
+for svc in db rabbitmq zookeeper kafka keycloak; do
+    printf "  %s: " "$svc"
+    until [ "$(docker inspect --format='{{.State.Health.Status}}' 
"airavata-$svc" 2>/dev/null)" = "healthy" ]; do
+        printf "."
+        sleep 3
+    done
+    echo " ready"
 done
-echo "  RabbitMQ: ready"
+echo "All infrastructure healthy."
 
 # 2. Generate keystores if missing
 if [ ! -f "$ROOT_DIR/keystores/airavata.p12" ]; then


Reply via email to