From 712b66422b1c43fd884bf631389827a621b0fab8 Mon Sep 17 00:00:00 2001 From: dtoro Date: Sat, 8 Aug 2026 22:17:44 +0200 Subject: [PATCH] =?UTF-8?q?0.28.5=20=E2=80=94=20nomos=20healthcheck=20fast?= =?UTF-8?q?-path=20before=20Infisical=20init?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The healthcheck subcommand was reachable only after main()'s Infisical secrets resolution (4x retries/key, ~30s when Infisical is down), which blew the 5s Docker healthcheck timeout — so nomos stayed docker-unhealthy despite serving /healthz fine. Short-circuit 'nomos healthcheck' at the top of main() before any secrets init; measured 0.58s, no Infisical retries. --- VERSION | 2 +- cmd/nomos/main.go | 54 ++++++++++++++++++++++++++++------------------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/VERSION b/VERSION index 097bc93..16b6bce 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.28.4 +0.28.5 diff --git a/cmd/nomos/main.go b/cmd/nomos/main.go index 9017709..c1e3c22 100644 --- a/cmd/nomos/main.go +++ b/cmd/nomos/main.go @@ -28,6 +28,15 @@ func main() { fmt.Fprintln(os.Stderr, "usage: nomos serve") os.Exit(1) } + // Fast-path the Docker healthcheck BEFORE any Infisical/secrets init. The + // nomos runtime image is distroless (no shell/wget), so the container + // probes itself via `nomos healthcheck`. Secrets resolution retries + // Infisical ~4x per key when it's down (~30s), which would blow the 5s + // healthcheck timeout — so this must run first and stay trivial. + if os.Args[1] == "healthcheck" { + runHealthcheck() + return + } mcpURL := os.Getenv("NOMOS_MCP_URL") if mcpURL == "" { mcpURL = "http://localhost:8090/mcp" @@ -186,34 +195,35 @@ func main() { srv.Shutdown(context.Background()) clientPool.closeAll() - case "healthcheck": - // Self-probe for Docker healthcheck. The nomos runtime image is - // distroless (no shell/wget), so the container can't run wget — the - // binary probes its own /healthz instead. Exit 0 on 200, 1 otherwise. - addr := os.Getenv("NOMOS_LISTEN") - if addr == "" { - addr = ":8092" - } - host := addr - if strings.HasPrefix(host, ":") { - host = "127.0.0.1" + host - } - client := &http.Client{Timeout: 3 * time.Second} - resp, err := client.Get("http://" + strings.TrimPrefix(host, "http://") + "/healthz") - if err != nil { - os.Exit(1) - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - os.Exit(1) - } - default: fmt.Fprintf(os.Stderr, "unknown command: %s\n", os.Args[1]) os.Exit(1) } } +// runHealthcheck self-probes NOMOS_LISTEN/healthz and exits 0 on HTTP 200, +// 1 otherwise. Used by the Docker healthcheck (the distroless runtime image +// has no wget/shell). Must stay fast — call it before any secrets init. +func runHealthcheck() { + addr := os.Getenv("NOMOS_LISTEN") + if addr == "" { + addr = ":8092" + } + host := addr + if strings.HasPrefix(host, ":") { + host = "127.0.0.1" + host + } + client := &http.Client{Timeout: 3 * time.Second} + resp, err := client.Get("http://" + host + "/healthz") + if err != nil { + os.Exit(1) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + os.Exit(1) + } +} + func sseEvent(w http.ResponseWriter, flusher http.Flusher, event agentEvent) { data, _ := json.Marshal(event) fmt.Fprintf(w, "data: %s\n\n", data)