diff --git a/pom.xml b/pom.xml index 88e8933..6562040 100644 --- a/pom.xml +++ b/pom.xml @@ -49,15 +49,15 @@ 2.1.0-alpha1 - 2.25.4 + 2.26.0 - 12.1.8 + 12.1.10 - 3.1.11 + 3.1.12 2.3.3.RELEASE - 6.1.0-SNAPSHOT + 6.1.0 6.1.0-1-SNAPSHOT 6.1.0-1-SNAPSHOT 5.6.0-1-SNAPSHOT @@ -67,7 +67,7 @@ 4.7.7 - 2.21 + 2.22 2.10.0 3.5.0 @@ -84,6 +84,30 @@ UTF-8 AKSW 1.7.0 + + 2.1.1 + 1.20.0 + 5.13.5.202508271544-r + 0.0.9 + 0.0.9 + 0.0.9 + 0.0.1-3 + 4.8.184 + 4.13.2 + + 1.6.0 + 3.15.0 + 3.4.0 + 2.10.4 + 3.6.0-M1 + 3.5.1 + 1.14 + 1.13.0 + 2.4.3 + 1.6 + 2.8.2 + 3.11.0 + 1.21.0 @@ -124,7 +148,7 @@ javax.ws.rs javax.ws.rs-api - 2.1.1 + ${ws.rs-api.version} @@ -317,40 +341,40 @@ org.locationtech.jts.io jts-io-common - 1.18.1 + ${jts-io-common.version} org.eclipse.jgit org.eclipse.jgit - 5.6.0.201912101111-r + ${jgit.version} com.jcraft jsch.agentproxy.jsch - 0.0.9 + ${jsch.agentproxy.jsch.version} com.jcraft jsch.agentproxy.usocket-jna - 0.0.9 + ${jsch.agentproxy.usocket-jna.version} com.jcraft jsch.agentproxy.sshagent - 0.0.9 + ${jsch.agentproxy.sshagent.version} org.aksw.thirdparty.com.sshtools vfs2nio - 0.0.1-3-SNAPSHOT + ${vfs2nio.version} io.github.classgraph classgraph - 4.8.129 + ${classgraph.version} @@ -379,7 +403,7 @@ junit junit - 4.13.1 + ${junit.version} @@ -420,12 +444,12 @@ de.jutzig github-release-plugin - 1.4.0 + ${github-release-plugin.version} com.amashchenko.maven.plugin gitflow-maven-plugin - 1.8.0 + ${gitflow-maven-plugin.version} v @@ -435,7 +459,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + ${maven-compiler-plugin.version} @@ -447,7 +471,7 @@ org.apache.maven.plugins maven-source-plugin - 3.0.1 + ${maven-source-plugin.version} attach-sources @@ -461,7 +485,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.9.1 + ${maven-javadoc-plugin.version} attach-javadocs @@ -480,7 +504,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.2.2 + ${maven-surefire-plugin.version} @@ -495,22 +519,22 @@ com.google.cloud.tools jib-maven-plugin - 3.4.4 + ${jib-maven-plugin.version} jdeb org.vafer - 1.10 + ${jdeb.version} de.dentrassi.maven rpm - 1.8.0 + ${rpm.version} org.apache.maven.plugins maven-shade-plugin - 2.4.3 + ${maven-shade-plugin.version} package @@ -542,7 +566,7 @@ org.apache.maven.plugins maven-gpg-plugin - 1.6 + ${maven-gpg-plugin.version} sign-artifacts @@ -571,12 +595,12 @@ org.apache.maven.plugins maven-deploy-plugin - 2.8.2 + ${maven-deploy-plugin.version} org.apache.maven.plugins maven-dependency-plugin - 3.0.2 + ${maven-dependency-plugin.version} prepare-package diff --git a/rdf-processing-toolkit-cli/src/main/java/org/aksw/sparql_integrate/cli/main/ServletRptServerStatus.java b/rdf-processing-toolkit-cli/src/main/java/org/aksw/sparql_integrate/cli/main/ServletRptServerStatus.java new file mode 100644 index 0000000..40a4121 --- /dev/null +++ b/rdf-processing-toolkit-cli/src/main/java/org/aksw/sparql_integrate/cli/main/ServletRptServerStatus.java @@ -0,0 +1,66 @@ +package org.aksw.sparql_integrate.cli.main; + +import jakarta.servlet.ServletRegistration; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.ws.rs.core.MediaType; +import org.aksw.jenax.web.server.boot.ServletBuilder; +import org.springframework.web.WebApplicationInitializer; +import org.springframework.web.context.support.GenericWebApplicationContext; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; + +public class ServletRptServerStatus extends HttpServlet implements ServletBuilder { + + private AtomicBoolean serverReady = null; + + public static ServletRptServerStatus newBuilder() { + return new ServletRptServerStatus(); + } + + @Override + public WebApplicationInitializer build(GenericWebApplicationContext rootContext) { + Objects.requireNonNull(serverReady, "Ready signal was not configured"); + return servletContext -> { + ServletRegistration.Dynamic servlet = servletContext.addServlet("rptServerStatus", this); + servlet.addMapping("/health"); + servlet.addMapping("/health/"); + servlet.setLoadOnStartup(1); + }; + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + String accept = req.getHeader("Accept"); + boolean isSse = accept != null && accept.contains("text/event-stream"); + + if (false && isSse) { + resp.setContentType("text/event-stream;charset=utf-8"); + resp.setHeader("Cache-Control", "no-cache"); + resp.setHeader("Connection", "keep-alive"); + + PrintWriter writer = resp.getWriter(); + writer.print("data: " + (serverReady.get() ? "ready" : "starting") + "\n\n"); + writer.flush(); + // XXX Would need to keep the connection open for SSE + } else { + resp.setContentType(MediaType.TEXT_PLAIN); + PrintWriter writer = resp.getWriter(); + writer.println(serverReady.get() ? "ready" : "starting"); + writer.close(); + } + } + + public ServletRptServerStatus setServerReady(AtomicBoolean serverReady) { + this.serverReady = serverReady; + return this; + } + + public boolean isServerReady() { + return serverReady.get(); + } +} diff --git a/rdf-processing-toolkit-cli/src/main/java/org/aksw/sparql_integrate/cli/main/SparqlIntegrateCmdImpls.java b/rdf-processing-toolkit-cli/src/main/java/org/aksw/sparql_integrate/cli/main/SparqlIntegrateCmdImpls.java index dce9880..c668fc2 100644 --- a/rdf-processing-toolkit-cli/src/main/java/org/aksw/sparql_integrate/cli/main/SparqlIntegrateCmdImpls.java +++ b/rdf-processing-toolkit-cli/src/main/java/org/aksw/sparql_integrate/cli/main/SparqlIntegrateCmdImpls.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.Optional; import java.util.Set; import java.util.function.Consumer; @@ -218,6 +219,8 @@ public static int sparqlIntegrate(CmdSparqlIntegrateMain cmd) throws Exception { CmdMixinArq.configureGlobal(cmd.arqConfig); CmdMixinArq.configureCxt(ARQ.getContext(), cmd.arqConfig); + AtomicBoolean serverReady = new AtomicBoolean(); + // JenaRuntime.isRDF11 = !cmd.useRdf10; // // CliUtils.configureGlobalSettings(); @@ -971,7 +974,9 @@ public void afterExec() { // .addServletBuilder(ServletBuilderGraphQlV2.newBuilder().setGraphQlExecFactory(graphQlExecFactory)) .addServletBuilder( ServletBuilderGraphQlV2.newBuilder().setGraphQlExecFactory(graphQlExecFactoryV2)) - .addServletBuilder(ServletLdvConfigJs.newBuilder().setDbEngine(cmd.engine)).setPort(port); + .addServletBuilder(ServletLdvConfigJs.newBuilder().setDbEngine(cmd.engine)) + .addServletBuilder(ServletRptServerStatus.newBuilder().setServerReady(serverReady)) + .setPort(port); if (graphqlSchemaNavigator != null) { serverBuilder = serverBuilder.addServletBuilder(ServletGraphQlSchema.newBuilder() @@ -1040,6 +1045,8 @@ public void afterExec() { logger.info("SPARQL overall execution finished after " + sw.stop()); if (server != null) { + serverReady.set(true); + // ServletRptServerStatus.setServerReady(); logger.info("Server still running on port " + cmd.serverPort + ". Terminate with CTRL+C"); server.join(); } diff --git a/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-deb-cli/src/deb/resources/usr/bin/rpt-integrate-await b/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-deb-cli/src/deb/resources/usr/bin/rpt-integrate-await new file mode 100755 index 0000000..81b8d10 --- /dev/null +++ b/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-deb-cli/src/deb/resources/usr/bin/rpt-integrate-await @@ -0,0 +1,145 @@ +#!/bin/bash + +# rpt-integrate-await: Wrapper script that starts rpt integrate --server +# and waits for the server to be ready via SSE health check +# Returns the PID of the rpt process once server is healthy + +set -e + +# Default values +DEFAULT_PORT=8642 +DEFAULT_TIMEOUT=30 +HEALTH_ENDPOINT="/health" + +# Arrays to store parsed arguments +RPT_ARGS=() +SERVER_MODE=false +SERVER_PORT=$DEFAULT_PORT + +# Parse command line arguments +while [[ $# -gt 0 ]]; do + case "$1" in + --server) + SERVER_MODE=true + RPT_ARGS+=("$1") + shift + ;; + --port) + if [[ -n "$2" && ! "$2" == --* ]]; then + SERVER_PORT="$2" + RPT_ARGS+=("$1" "$2") + shift 2 + else + # Handle --port= format + SERVER_PORT="${1#--port=}" + RPT_ARGS+=("$1") + shift + fi + ;; + --help|-h) + echo "Usage: rpt-integrate-await [options] " + echo "" + echo "Wrapper script for 'rpt integrate --server' that waits for the server to be ready." + echo "" + echo "Options:" + echo " --port= Server port (default: ${DEFAULT_PORT})" + echo " --timeout= Wait timeout in seconds (default: ${DEFAULT_TIMEOUT})" + echo " --help, -h Show this help message" + echo "" + echo "All other arguments are passed to 'rpt integrate'." + echo "The server must be started with --server flag." + echo "" + echo "Returns the PID of the rpt process once the server is healthy." + exit 0 + ;; + --timeout) + if [[ -n "$2" && ! "$2" == --* ]]; then + TIMEOUT="$2" + shift 2 + else + TIMEOUT="${1#--timeout=}" + shift + fi + ;; + *) + RPT_ARGS+=("$1") + shift + ;; + esac +done + +# Set default timeout if not specified +TIMEOUT=${TIMEOUT:-$DEFAULT_TIMEOUT} + +# Check if --server is in arguments +if [[ "$SERVER_MODE" != "true" ]]; then + echo "Error: 'rpt-integrate-await' requires the --server flag" >&2 + echo "Usage: rpt-integrate-await --server [options] " >&2 + exit 1 +fi + +# Build the health check URL +HEALTH_URL="http://localhost:${SERVER_PORT}${HEALTH_ENDPOINT}" + +# Start rpt integrate in background +# Note: We use 'rpt integrate' instead of the full path to respect the user's environment +rpt integrate "${RPT_ARGS[@]}" > /dev/null & # 2>&1 would hide log output +RPT_PID=$! + +# Function to check if process is running +is_process_running() { + kill -0 "$RPT_PID" 2>/dev/null +} + +# Wait for server to become available using SSE +echo "Waiting for server to start on port ${SERVER_PORT}..." >&2 +echo "Health check endpoint: ${HEALTH_URL}" >&2 + +# Try to connect with SSE for up to TIMEOUT seconds +START_TIME=$(date +%s) +HEALTHY=false + +while true; do + CURRENT_TIME=$(date +%s) + ELAPSED=$((CURRENT_TIME - START_TIME)) + + if [[ $ELAPSED -ge $TIMEOUT ]]; then + echo "Error: Timeout waiting for server to start after ${TIMEOUT} seconds" >&2 + kill "$RPT_PID" 2>/dev/null || true + exit 1 + fi + + # Check if rpt process is still running + if ! is_process_running; then + echo "Error: rpt process exited unexpectedly" >&2 + exit 1 + fi + + # Try to connect with SSE using curl + if curl --no-buffer --silent --fail --max-time 2 --header "Accept: text/event-stream" "$HEALTH_URL" --connect-timeout 1 > /dev/null 2>&1; then + # Health check passed, now verify port ownership + ACTUAL_PID=$(lsof -t -i :${SERVER_PORT} 2>/dev/null | head -1) + + if [[ -z "$ACTUAL_PID" ]]; then + sleep 0.5 + continue + fi + + if [[ "$ACTUAL_PID" != "$RPT_PID" ]]; then + echo "Error: Port ${SERVER_PORT} is owned by PID ${ACTUAL_PID}, not our process ${RPT_PID}" >&2 + exit 1 + # sleep 0.5 + # continue + fi + + echo "Server is ready!" >&2 + HEALTHY=true + break + fi + + sleep 0.5 +done + +# Output the PID to stdout so the caller can capture it +echo "$RPT_PID" + diff --git a/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-docker-cli/pom.xml b/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-docker-cli/pom.xml index efe7b51..825015f 100644 --- a/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-docker-cli/pom.xml +++ b/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-docker-cli/pom.xml @@ -48,7 +48,7 @@ - eclipse-temurin:17-jre + eclipse-temurin:21-jre org.aksw.rdf_processing_toolkit.cli.main.MainCliRdfProcessingToolkit @@ -70,6 +70,20 @@ --add-opens=java.security.jgss/sun.security.krb5=ALL-UNNAMED + + + + src/main/jib + / + + + + + /usr/bin/rpt-integrate-await + 755 + + + packaged diff --git a/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-docker-cli/src/main/jib/usr/bin/rpt-integrate-await b/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-docker-cli/src/main/jib/usr/bin/rpt-integrate-await new file mode 100755 index 0000000..81b8d10 --- /dev/null +++ b/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-docker-cli/src/main/jib/usr/bin/rpt-integrate-await @@ -0,0 +1,145 @@ +#!/bin/bash + +# rpt-integrate-await: Wrapper script that starts rpt integrate --server +# and waits for the server to be ready via SSE health check +# Returns the PID of the rpt process once server is healthy + +set -e + +# Default values +DEFAULT_PORT=8642 +DEFAULT_TIMEOUT=30 +HEALTH_ENDPOINT="/health" + +# Arrays to store parsed arguments +RPT_ARGS=() +SERVER_MODE=false +SERVER_PORT=$DEFAULT_PORT + +# Parse command line arguments +while [[ $# -gt 0 ]]; do + case "$1" in + --server) + SERVER_MODE=true + RPT_ARGS+=("$1") + shift + ;; + --port) + if [[ -n "$2" && ! "$2" == --* ]]; then + SERVER_PORT="$2" + RPT_ARGS+=("$1" "$2") + shift 2 + else + # Handle --port= format + SERVER_PORT="${1#--port=}" + RPT_ARGS+=("$1") + shift + fi + ;; + --help|-h) + echo "Usage: rpt-integrate-await [options] " + echo "" + echo "Wrapper script for 'rpt integrate --server' that waits for the server to be ready." + echo "" + echo "Options:" + echo " --port= Server port (default: ${DEFAULT_PORT})" + echo " --timeout= Wait timeout in seconds (default: ${DEFAULT_TIMEOUT})" + echo " --help, -h Show this help message" + echo "" + echo "All other arguments are passed to 'rpt integrate'." + echo "The server must be started with --server flag." + echo "" + echo "Returns the PID of the rpt process once the server is healthy." + exit 0 + ;; + --timeout) + if [[ -n "$2" && ! "$2" == --* ]]; then + TIMEOUT="$2" + shift 2 + else + TIMEOUT="${1#--timeout=}" + shift + fi + ;; + *) + RPT_ARGS+=("$1") + shift + ;; + esac +done + +# Set default timeout if not specified +TIMEOUT=${TIMEOUT:-$DEFAULT_TIMEOUT} + +# Check if --server is in arguments +if [[ "$SERVER_MODE" != "true" ]]; then + echo "Error: 'rpt-integrate-await' requires the --server flag" >&2 + echo "Usage: rpt-integrate-await --server [options] " >&2 + exit 1 +fi + +# Build the health check URL +HEALTH_URL="http://localhost:${SERVER_PORT}${HEALTH_ENDPOINT}" + +# Start rpt integrate in background +# Note: We use 'rpt integrate' instead of the full path to respect the user's environment +rpt integrate "${RPT_ARGS[@]}" > /dev/null & # 2>&1 would hide log output +RPT_PID=$! + +# Function to check if process is running +is_process_running() { + kill -0 "$RPT_PID" 2>/dev/null +} + +# Wait for server to become available using SSE +echo "Waiting for server to start on port ${SERVER_PORT}..." >&2 +echo "Health check endpoint: ${HEALTH_URL}" >&2 + +# Try to connect with SSE for up to TIMEOUT seconds +START_TIME=$(date +%s) +HEALTHY=false + +while true; do + CURRENT_TIME=$(date +%s) + ELAPSED=$((CURRENT_TIME - START_TIME)) + + if [[ $ELAPSED -ge $TIMEOUT ]]; then + echo "Error: Timeout waiting for server to start after ${TIMEOUT} seconds" >&2 + kill "$RPT_PID" 2>/dev/null || true + exit 1 + fi + + # Check if rpt process is still running + if ! is_process_running; then + echo "Error: rpt process exited unexpectedly" >&2 + exit 1 + fi + + # Try to connect with SSE using curl + if curl --no-buffer --silent --fail --max-time 2 --header "Accept: text/event-stream" "$HEALTH_URL" --connect-timeout 1 > /dev/null 2>&1; then + # Health check passed, now verify port ownership + ACTUAL_PID=$(lsof -t -i :${SERVER_PORT} 2>/dev/null | head -1) + + if [[ -z "$ACTUAL_PID" ]]; then + sleep 0.5 + continue + fi + + if [[ "$ACTUAL_PID" != "$RPT_PID" ]]; then + echo "Error: Port ${SERVER_PORT} is owned by PID ${ACTUAL_PID}, not our process ${RPT_PID}" >&2 + exit 1 + # sleep 0.5 + # continue + fi + + echo "Server is ready!" >&2 + HEALTHY=true + break + fi + + sleep 0.5 +done + +# Output the PID to stdout so the caller can capture it +echo "$RPT_PID" + diff --git a/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-docker-cli/test-jib-files.xml b/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-docker-cli/test-jib-files.xml new file mode 100644 index 0000000..0bed001 --- /dev/null +++ b/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-docker-cli/test-jib-files.xml @@ -0,0 +1,31 @@ + + 4.0.0 + test + test + 1.0 + + + + com.google.cloud.tools + jib-maven-plugin + 3.4.4 + + + eclipse-temurin:17-jre + + + test:latest + + + + + /etc/hostname + /test-file + + + + + + + + diff --git a/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-rpm-cli/src/rpm/resources/usr/bin/rpt-integrate-await b/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-rpm-cli/src/rpm/resources/usr/bin/rpt-integrate-await new file mode 100755 index 0000000..81b8d10 --- /dev/null +++ b/rdf-processing-toolkit-pkg-parent/rdf-processing-toolkit-pkg-rpm-cli/src/rpm/resources/usr/bin/rpt-integrate-await @@ -0,0 +1,145 @@ +#!/bin/bash + +# rpt-integrate-await: Wrapper script that starts rpt integrate --server +# and waits for the server to be ready via SSE health check +# Returns the PID of the rpt process once server is healthy + +set -e + +# Default values +DEFAULT_PORT=8642 +DEFAULT_TIMEOUT=30 +HEALTH_ENDPOINT="/health" + +# Arrays to store parsed arguments +RPT_ARGS=() +SERVER_MODE=false +SERVER_PORT=$DEFAULT_PORT + +# Parse command line arguments +while [[ $# -gt 0 ]]; do + case "$1" in + --server) + SERVER_MODE=true + RPT_ARGS+=("$1") + shift + ;; + --port) + if [[ -n "$2" && ! "$2" == --* ]]; then + SERVER_PORT="$2" + RPT_ARGS+=("$1" "$2") + shift 2 + else + # Handle --port= format + SERVER_PORT="${1#--port=}" + RPT_ARGS+=("$1") + shift + fi + ;; + --help|-h) + echo "Usage: rpt-integrate-await [options] " + echo "" + echo "Wrapper script for 'rpt integrate --server' that waits for the server to be ready." + echo "" + echo "Options:" + echo " --port= Server port (default: ${DEFAULT_PORT})" + echo " --timeout= Wait timeout in seconds (default: ${DEFAULT_TIMEOUT})" + echo " --help, -h Show this help message" + echo "" + echo "All other arguments are passed to 'rpt integrate'." + echo "The server must be started with --server flag." + echo "" + echo "Returns the PID of the rpt process once the server is healthy." + exit 0 + ;; + --timeout) + if [[ -n "$2" && ! "$2" == --* ]]; then + TIMEOUT="$2" + shift 2 + else + TIMEOUT="${1#--timeout=}" + shift + fi + ;; + *) + RPT_ARGS+=("$1") + shift + ;; + esac +done + +# Set default timeout if not specified +TIMEOUT=${TIMEOUT:-$DEFAULT_TIMEOUT} + +# Check if --server is in arguments +if [[ "$SERVER_MODE" != "true" ]]; then + echo "Error: 'rpt-integrate-await' requires the --server flag" >&2 + echo "Usage: rpt-integrate-await --server [options] " >&2 + exit 1 +fi + +# Build the health check URL +HEALTH_URL="http://localhost:${SERVER_PORT}${HEALTH_ENDPOINT}" + +# Start rpt integrate in background +# Note: We use 'rpt integrate' instead of the full path to respect the user's environment +rpt integrate "${RPT_ARGS[@]}" > /dev/null & # 2>&1 would hide log output +RPT_PID=$! + +# Function to check if process is running +is_process_running() { + kill -0 "$RPT_PID" 2>/dev/null +} + +# Wait for server to become available using SSE +echo "Waiting for server to start on port ${SERVER_PORT}..." >&2 +echo "Health check endpoint: ${HEALTH_URL}" >&2 + +# Try to connect with SSE for up to TIMEOUT seconds +START_TIME=$(date +%s) +HEALTHY=false + +while true; do + CURRENT_TIME=$(date +%s) + ELAPSED=$((CURRENT_TIME - START_TIME)) + + if [[ $ELAPSED -ge $TIMEOUT ]]; then + echo "Error: Timeout waiting for server to start after ${TIMEOUT} seconds" >&2 + kill "$RPT_PID" 2>/dev/null || true + exit 1 + fi + + # Check if rpt process is still running + if ! is_process_running; then + echo "Error: rpt process exited unexpectedly" >&2 + exit 1 + fi + + # Try to connect with SSE using curl + if curl --no-buffer --silent --fail --max-time 2 --header "Accept: text/event-stream" "$HEALTH_URL" --connect-timeout 1 > /dev/null 2>&1; then + # Health check passed, now verify port ownership + ACTUAL_PID=$(lsof -t -i :${SERVER_PORT} 2>/dev/null | head -1) + + if [[ -z "$ACTUAL_PID" ]]; then + sleep 0.5 + continue + fi + + if [[ "$ACTUAL_PID" != "$RPT_PID" ]]; then + echo "Error: Port ${SERVER_PORT} is owned by PID ${ACTUAL_PID}, not our process ${RPT_PID}" >&2 + exit 1 + # sleep 0.5 + # continue + fi + + echo "Server is ready!" >&2 + HEALTHY=true + break + fi + + sleep 0.5 +done + +# Output the PID to stdout so the caller can capture it +echo "$RPT_PID" +