diff --git a/pkg/server/server.go b/pkg/server/server.go index 4e2163e..4686274 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -24,6 +24,7 @@ import ( userapi "dance-lessons-coach/pkg/user/api" "dance-lessons-coach/pkg/validation" "dance-lessons-coach/pkg/version" + "encoding/json" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" sdktrace "go.opentelemetry.io/otel/sdk/trace" @@ -213,12 +214,12 @@ func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) { // handleReadiness godoc // // @Summary Readiness check -// @Description Check if the service is ready to accept traffic including database connectivity +// @Description Check if the service is ready to accept traffic including detailed connection status // @Tags System/Health // @Accept json // @Produce json -// @Success 200 {object} map[string]bool "Service is ready" -// @Failure 503 {object} map[string]bool "Service is not ready" +// @Success 200 {object} object "Service is ready with connection details" +// @Failure 503 {object} object "Service is not ready with failure details" // @Router /ready [get] func (s *Server) handleReadiness(w http.ResponseWriter, r *http.Request) { log.Trace().Msg("Readiness check requested") @@ -227,21 +228,61 @@ func (s *Server) handleReadiness(w http.ResponseWriter, r *http.Request) { select { case <-s.readyCtx.Done(): log.Trace().Msg("Readiness check: not ready (shutting down)") + w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusServiceUnavailable) - w.Write([]byte(`{"ready":false}`)) + json.NewEncoder(w).Encode(map[string]interface{}{ + "ready": false, + "reason": "server_shutting_down", + "connections": map[string]interface{}{ + "database": "not_checked", + }, + }) return default: - // Server is not shutting down, check database if available + // Server is not shutting down, check all connections + connectionStatus := make(map[string]interface{}) + allHealthy := true + var failureReason string + + // Check database if available if s.userRepo != nil { if err := s.userRepo.CheckDatabaseHealth(r.Context()); err != nil { log.Warn().Err(err).Msg("Database health check failed") - w.WriteHeader(http.StatusServiceUnavailable) - w.Write([]byte(`{"ready":false}`)) - return + connectionStatus["database"] = map[string]interface{}{ + "status": "unhealthy", + "error": err.Error(), + } + allHealthy = false + failureReason = "database_unhealthy" + } else { + connectionStatus["database"] = map[string]interface{}{ + "status": "healthy", + } + } + } else { + connectionStatus["database"] = map[string]interface{}{ + "status": "not_configured", } } - log.Trace().Msg("Readiness check: ready") - w.Write([]byte(`{"ready":true}`)) + + if allHealthy { + log.Trace().Msg("Readiness check: ready") + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(map[string]interface{}{ + "ready": true, + "connections": connectionStatus, + }) + } else { + log.Warn().Str("reason", failureReason).Msg("Readiness check: not ready") + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusServiceUnavailable) + json.NewEncoder(w).Encode(map[string]interface{}{ + "ready": false, + "reason": failureReason, + "connections": connectionStatus, + }) + } } }