diff --git a/apps/server/src/main/kotlin/com/correx/apps/server/Main.kt b/apps/server/src/main/kotlin/com/correx/apps/server/Main.kt index ea2cdad8..97ba6a80 100644 --- a/apps/server/src/main/kotlin/com/correx/apps/server/Main.kt +++ b/apps/server/src/main/kotlin/com/correx/apps/server/Main.kt @@ -96,6 +96,9 @@ import java.nio.file.Paths private val log = LoggerFactory.getLogger("com.correx.apps.server.Main") +/** Per-ping timeout (ms) for the llama-server health probe — short so a hung server never stalls it. */ +private const val LLAMA_HEALTH_TIMEOUT_MS = 3_000L + fun main() { log.info("=== correx server starting ===") log.info(" port : 8080") @@ -438,9 +441,21 @@ fun main() { val seeded = DefaultEventReplayer(eventStore, com.correx.apps.server.health.HealthProjection()) .rebuild(com.correx.apps.server.health.SYSTEM_SESSION) .subjects.mapValues { it.value.status } + // Monitor the llama server only when a llamacpp provider URL is configured — otherwise the + // LLAMA_SERVER subject would report a spurious DEGRADED on a box that runs no local model. + // A dedicated short-timeout client keeps a hung server from stalling the probe loop. + val llamaProbe = correxConfig.providers.firstOrNull { it.type == "llamacpp" }?.url?.let { url -> + val healthHttpClient = io.ktor.client.HttpClient(io.ktor.client.engine.cio.CIO) { + engine { requestTimeout = LLAMA_HEALTH_TIMEOUT_MS } + } + Runtime.getRuntime().addShutdownHook(Thread { healthHttpClient.close() }) + com.correx.apps.server.health.LlamaServerHealthProbe( + com.correx.apps.server.health.HttpLlamaLivenessClient(healthHttpClient, url), + ) + } com.correx.apps.server.health.HealthMonitor( eventStore = eventStore, - probes = listOf( + probes = listOfNotNull( com.correx.apps.server.health.DiskWatermarkProbe( monitoredPaths = listOf(dataDir), warnBytes = hc.diskWarnBytes, @@ -450,9 +465,7 @@ fun main() { eventStore, hc.eventStoreWarnLatencyMs, ), - // TODO(wiring): register LlamaServerHealthProbe once an HttpClient + tokens/sec telemetry are - // exposed to the health-monitor scope (currently only built inside - // InfrastructureModule.createModelManager). + llamaProbe, ), intervalMs = hc.intervalMs, initialStatuses = seeded,