From 81d3c5a3bd5354e2d4636ff674d6adb1f2fb5621 Mon Sep 17 00:00:00 2001 From: F04C Date: Mon, 5 Jan 2026 14:41:25 +0800 Subject: [PATCH] added health routes --- handlers/health.go | 77 ++++++++++++++++++++++++++++++++++++++++++++++ main.go | 2 +- models/health.go | 7 +++++ routes/routes.go | 6 +++- 4 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 handlers/health.go create mode 100644 models/health.go diff --git a/handlers/health.go b/handlers/health.go new file mode 100644 index 0000000..de14ce5 --- /dev/null +++ b/handlers/health.go @@ -0,0 +1,77 @@ +package handlers + +import ( + "authentication/db" + "authentication/models" + "authentication/redisclient" + "context" + "encoding/json" + "net/http" + "time" +) + +func HealthHandler(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(models.HealthResponse{ + Status: "ok", + }) +} + +// ReadyHandler checks if the service is ready to handle requests +// @Summary Readiness check endpoint +// @Description Returns readiness status including database and Redis connectivity +// @Tags health +// @Produce json +// @Success 200 {object} HealthResponse +// @Failure 503 {object} HealthResponse +// @Router /ready [get] +func ReadyHandler(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + + services := make(map[string]string) + allHealthy := true + + // Check database + if db.DB != nil { + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + if err := db.DB.PingContext(ctx); err != nil { + services["database"] = "unhealthy" + allHealthy = false + } else { + services["database"] = "healthy" + } + } else { + services["database"] = "not_initialized" + allHealthy = false + } + + // Check Redis + if redisclient.RDB != nil { + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + if _, err := redisclient.RDB.Ping(ctx).Result(); err != nil { + services["redis"] = "unhealthy" + allHealthy = false + } else { + services["redis"] = "healthy" + } + } else { + services["redis"] = "not_initialized" + allHealthy = false + } + + status := "ready" + statusCode := http.StatusOK + if !allHealthy { + status = "not_ready" + statusCode = http.StatusServiceUnavailable + } + + w.WriteHeader(statusCode) + json.NewEncoder(w).Encode(models.HealthResponse{ + Status: status, + Services: services, + }) +} diff --git a/main.go b/main.go index d080ea4..2f78b4d 100644 --- a/main.go +++ b/main.go @@ -241,7 +241,7 @@ func main() { helper.LogInfo("INFO: Authentication Microservice is running on http://localhost:8081") server := &http.Server{ - Addr: ":8081", + Addr: ":8080", Handler: handler, ReadTimeout: 15 * time.Second, WriteTimeout: 300 * time.Second, diff --git a/models/health.go b/models/health.go new file mode 100644 index 0000000..947cdf0 --- /dev/null +++ b/models/health.go @@ -0,0 +1,7 @@ +package models + +// HealthResponse represents the health check response +type HealthResponse struct { + Status string `json:"status"` + Services map[string]string `json:"services,omitempty"` +} diff --git a/routes/routes.go b/routes/routes.go index 85c641b..c314c4f 100644 --- a/routes/routes.go +++ b/routes/routes.go @@ -9,6 +9,10 @@ import ( ) func SetupRoutes(router *mux.Router, db *sql.DB) { + + router.HandleFunc("/health", handlers.HealthHandler).Methods("GET") + router.HandleFunc("/ready", handlers.ReadyHandler).Methods("GET") + authRoutes := router.PathPrefix("/v1/auth").Subrouter() authRoutes.HandleFunc("/login", handlers.GoogleLogin).Methods("GET") authRoutes.HandleFunc("/callback", handlers.GoogleCallback).Methods("GET") @@ -16,7 +20,7 @@ func SetupRoutes(router *mux.Router, db *sql.DB) { authRoutes.HandleFunc("/logout", handlers.LogoutHandler).Methods("GET") // authRoutes.HandleFunc("/microsoft/login", handlers.MicrosoftLogin).Methods("GET") - // authRoutes.HandleFunc("/microsoft/callback", handlers.MicrosoftCallback).Methods("GET") + // authRoutes.HandleFunc("/microsoft/callback", handlers.MicrosotCallback).Methods("GET") router.PathPrefix("/swagger/").Handler(httpSwagger.WrapHandler) }