package server import ( "net/http" "sync" ) // HealthChecker provides health and readiness check information. type HealthChecker struct { mu sync.RWMutex configValid bool jwksHasFetched bool authEnabled bool } // NewHealthChecker creates a new health checker instance. func NewHealthChecker(configValid bool, authEnabled bool) *HealthChecker { return &HealthChecker{ configValid: configValid, jwksHasFetched: false, authEnabled: authEnabled, } } // MarkJWKSFetched marks that JWKS has been fetched successfully. func (hc *HealthChecker) MarkJWKSFetched() { hc.mu.Lock() defer hc.mu.Unlock() hc.jwksHasFetched = true } // IsReady checks if the server is ready to serve traffic. // It returns true if: // - Configuration is valid // - If auth is enabled, JWKS has been fetched at least once func (hc *HealthChecker) IsReady() bool { hc.mu.RLock() defer hc.mu.RUnlock() if !hc.configValid { return false } // If auth is enabled, we must have fetched JWKS at least once if hc.authEnabled && !hc.jwksHasFetched { return false } return true } // IsAlive returns true if the process is running. // This is always true since if it weren't, we wouldn't be running this code. func (hc *HealthChecker) IsAlive() bool { return true } // LivenessHandler returns a handler for the /healthz endpoint. // It returns 200 whenever the process is alive. // It performs no network I/O. func LivenessHandler(hc *HealthChecker) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if !hc.IsAlive() { w.WriteHeader(http.StatusServiceUnavailable) return } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) w.Write([]byte(`{"status":"alive"}`)) } } // ReadinessHandler returns a handler for the /readyz endpoint. // It returns 200 only when configuration is valid and, if auth is enabled, // JWKS has been fetched at least once. // It returns non-2xx status while configuration is invalid or JWKS has never // been fetched. func ReadinessHandler(hc *HealthChecker) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if !hc.IsReady() { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusServiceUnavailable) w.Write([]byte(`{"status":"not_ready"}`)) return } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) w.Write([]byte(`{"status":"ready"}`)) } }