0.28.5 — nomos healthcheck fast-path before Infisical init
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.
This commit is contained in:
@@ -28,6 +28,15 @@ func main() {
|
|||||||
fmt.Fprintln(os.Stderr, "usage: nomos serve")
|
fmt.Fprintln(os.Stderr, "usage: nomos serve")
|
||||||
os.Exit(1)
|
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")
|
mcpURL := os.Getenv("NOMOS_MCP_URL")
|
||||||
if mcpURL == "" {
|
if mcpURL == "" {
|
||||||
mcpURL = "http://localhost:8090/mcp"
|
mcpURL = "http://localhost:8090/mcp"
|
||||||
@@ -186,34 +195,35 @@ func main() {
|
|||||||
srv.Shutdown(context.Background())
|
srv.Shutdown(context.Background())
|
||||||
clientPool.closeAll()
|
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:
|
default:
|
||||||
fmt.Fprintf(os.Stderr, "unknown command: %s\n", os.Args[1])
|
fmt.Fprintf(os.Stderr, "unknown command: %s\n", os.Args[1])
|
||||||
os.Exit(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) {
|
func sseEvent(w http.ResponseWriter, flusher http.Flusher, event agentEvent) {
|
||||||
data, _ := json.Marshal(event)
|
data, _ := json.Marshal(event)
|
||||||
fmt.Fprintf(w, "data: %s\n\n", data)
|
fmt.Fprintf(w, "data: %s\n\n", data)
|
||||||
|
|||||||
Reference in New Issue
Block a user