scobleclaw/pool-manager/main.go
agent-cos 45b3b62389 feat(pool-manager): add /healthz handler for k8s liveness/readiness probes (#56)
- pool-manager/main.go: serve HTTP on :3990 with /healthz that does a 2s-context
  pgxpool.Ping; returns 200 OK when Postgres is reachable, 503 otherwise.
  Runs alongside the existing signal-blocking main loop.
- pool-manager/Dockerfile: distroless static-debian12 image exposing :3990.
- pool-manager/.gitignore: skip built pool-manager binary and *.tar.

Refs marcus/engineering#56
Closes marcus/engineering#56
2026-06-07 07:21:34 -07:00

59 lines
1.2 KiB
Go

package main
import (
"context"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"scobleclaw.dev/pool-manager/poolq"
"github.com/jackc/pgx/v5/pgxpool"
)
func main() {
dsn := os.Getenv("PG_DSN")
if dsn == "" {
dsn = "host=/var/run/postgresql dbname=postgres sslmode=disable"
}
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
pool, err := pgxpool.New(ctx, dsn)
if err != nil {
log.Fatalf("pgxpool: %v", err)
}
defer pool.Close()
if err := poolq.EnsureSchema(ctx, pool); err != nil {
log.Fatalf("ensure schema: %v", err)
}
log.Println("pool-manager schema ensured, poolq ready")
mux := http.NewServeMux()
mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
pingCtx, cancel := context.WithTimeout(r.Context(), 2*time.Second)
defer cancel()
if err := pool.Ping(pingCtx); err != nil {
w.WriteHeader(http.StatusServiceUnavailable)
fmt.Fprintln(w, "pg unreachable:", err)
return
}
w.WriteHeader(http.StatusOK)
fmt.Fprintln(w, "ok")
})
go func() {
log.Println("healthz server listening on :3990")
if err := http.ListenAndServe(":3990", mux); err != nil {
log.Fatalf("healthz server: %v", err)
}
}()
<-ctx.Done()
}