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