You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by ya...@apache.org on 2026/03/26 20:41:28 UTC
(airavata) 01/10: feat: add ServiceRegistry and ServiceStatus for background service tracking
This is an automated email from the ASF dual-hosted git repository.
yasith pushed a commit to branch AIRAVATA-3981/integration-health-check
in repository https://gitbox.apache.org/repos/asf/airavata.git
commit 2e94e32ae061939515b451976e72f7873774d195
Author: yasithdev <ya...@icloud.com>
AuthorDate: Thu Mar 26 15:27:30 2026 -0500
feat: add ServiceRegistry and ServiceStatus for background service tracking
---
.../patform/monitoring/ServiceRegistry.java | 149 +++++++++++++++++++++
.../airavata/patform/monitoring/ServiceStatus.java | 62 +++++++++
2 files changed, 211 insertions(+)
diff --git a/airavata-api/src/main/java/org/apache/airavata/patform/monitoring/ServiceRegistry.java b/airavata-api/src/main/java/org/apache/airavata/patform/monitoring/ServiceRegistry.java
new file mode 100644
index 0000000000..cce0eeb2c2
--- /dev/null
+++ b/airavata-api/src/main/java/org/apache/airavata/patform/monitoring/ServiceRegistry.java
@@ -0,0 +1,149 @@
+/**
+*
+* 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.patform.monitoring;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.function.Supplier;
+import org.apache.airavata.common.utils.IServer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Tracks background {@link IServer} instances and their threads, exposing
+ * lifecycle operations (status query, restart, stop-all) and error recording.
+ */
+public class ServiceRegistry {
+
+ private static final Logger logger = LoggerFactory.getLogger(ServiceRegistry.class);
+
+ private static class Entry {
+ final IServer server;
+ Thread thread;
+ final Supplier<IServer> factory;
+ final long startedAt;
+ String lastError;
+
+ Entry(IServer server, Thread thread, Supplier<IServer> factory) {
+ this.server = server;
+ this.thread = thread;
+ this.factory = factory;
+ this.startedAt = System.currentTimeMillis();
+ }
+ }
+
+ private final Map<String, Entry> entries = new LinkedHashMap<>();
+
+ /**
+ * Registers a service with an optional restart factory.
+ *
+ * @param label human-readable service identifier
+ * @param service the IServer instance
+ * @param thread the thread running the service
+ * @param factory optional supplier to create a fresh IServer for restart; may be null
+ */
+ public synchronized void register(String label, IServer service, Thread thread, Supplier<IServer> factory) {
+ entries.put(label, new Entry(service, thread, factory));
+ }
+
+ /**
+ * Registers a service without a restart factory.
+ */
+ public synchronized void register(String label, IServer service, Thread thread) {
+ register(label, service, thread, null);
+ }
+
+ /**
+ * Returns a snapshot of statuses keyed by label.
+ * Status is {@code "UP"} when the thread is alive, {@code "DOWN"} otherwise.
+ */
+ public synchronized Map<String, ServiceStatus> getStatuses() {
+ Map<String, ServiceStatus> result = new LinkedHashMap<>();
+ for (Map.Entry<String, Entry> e : entries.entrySet()) {
+ Entry entry = e.getValue();
+ String status = entry.thread.isAlive() ? "UP" : "DOWN";
+ long uptimeMs = entry.thread.isAlive() ? System.currentTimeMillis() - entry.startedAt : 0L;
+ result.put(e.getKey(), new ServiceStatus(status, uptimeMs, entry.lastError));
+ }
+ return result;
+ }
+
+ /**
+ * Attempts to restart the named service using its registered factory.
+ *
+ * @param name the service label
+ * @throws IllegalArgumentException if no service with that name exists
+ * @throws IllegalStateException if the service has no restart factory
+ * @throws Exception if the new service thread fails to start
+ */
+ public synchronized void restart(String name) throws Exception {
+ Entry entry = entries.get(name);
+ if (entry == null) {
+ throw new IllegalArgumentException("No service registered with name: " + name);
+ }
+ if (entry.factory == null) {
+ throw new IllegalStateException("Service '" + name + "' has no restart factory");
+ }
+ // Stop the old instance
+ try {
+ entry.server.stop();
+ } catch (Exception e) {
+ logger.warn("Error stopping '{}' before restart: {}", name, e.getMessage());
+ }
+ entry.thread.interrupt();
+
+ // Start a fresh instance
+ IServer newServer = entry.factory.get();
+ Thread newThread = new Thread(newServer, "airavata-" + name);
+ newThread.setDaemon(true);
+ newThread.start();
+
+ Entry newEntry = new Entry(newServer, newThread, entry.factory);
+ entries.put(name, newEntry);
+ logger.info("Service '{}' restarted", name);
+ }
+
+ /**
+ * Records an error message against the named service.
+ * Silently ignores unknown names.
+ */
+ public synchronized void recordError(String name, String errorMessage) {
+ Entry entry = entries.get(name);
+ if (entry != null) {
+ entry.lastError = errorMessage;
+ }
+ }
+
+ /**
+ * Stops all registered services and interrupts their threads.
+ */
+ public synchronized void stopAll() {
+ for (Map.Entry<String, Entry> e : entries.entrySet()) {
+ String label = e.getKey();
+ Entry entry = e.getValue();
+ try {
+ entry.server.stop();
+ } catch (Exception ex) {
+ logger.warn("Error stopping '{}': {}", label, ex.getMessage());
+ }
+ entry.thread.interrupt();
+ }
+ }
+}
diff --git a/airavata-api/src/main/java/org/apache/airavata/patform/monitoring/ServiceStatus.java b/airavata-api/src/main/java/org/apache/airavata/patform/monitoring/ServiceStatus.java
new file mode 100644
index 0000000000..9d1b48854a
--- /dev/null
+++ b/airavata-api/src/main/java/org/apache/airavata/patform/monitoring/ServiceStatus.java
@@ -0,0 +1,62 @@
+/**
+*
+* 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.patform.monitoring;
+
+/**
+ * DTO representing the runtime status of a single background service.
+ */
+public class ServiceStatus {
+
+ private String status;
+ private long uptimeMs;
+ private String lastError;
+
+ public ServiceStatus() {}
+
+ public ServiceStatus(String status, long uptimeMs, String lastError) {
+ this.status = status;
+ this.uptimeMs = uptimeMs;
+ this.lastError = lastError;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public long getUptimeMs() {
+ return uptimeMs;
+ }
+
+ public void setUptimeMs(long uptimeMs) {
+ this.uptimeMs = uptimeMs;
+ }
+
+ public String getLastError() {
+ return lastError;
+ }
+
+ public void setLastError(String lastError) {
+ this.lastError = lastError;
+ }
+}