From ffe96c8c65d0c2bb831c0175019ed3d71def8b1a Mon Sep 17 00:00:00 2001 From: chan Date: Tue, 20 Jan 2026 10:10:50 +0900 Subject: [PATCH] =?UTF-8?q?=ED=97=AC=EC=8A=A4=EC=B2=B4=ED=81=AC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/cmd/server/main.go | 69 ++++++++++++++++--- backend/internal/handler/auth_handler.go | 8 +-- .../internal/repository/clickhouse_repo.go | 7 ++ backend/internal/service/redis_service.go | 7 ++ docker-compose.yaml | 12 +++- docker/docker-compose.deploy.yaml | 9 ++- 6 files changed, 94 insertions(+), 18 deletions(-) diff --git a/backend/cmd/server/main.go b/backend/cmd/server/main.go index 8951cb40..f31f80d5 100644 --- a/backend/cmd/server/main.go +++ b/backend/cmd/server/main.go @@ -6,12 +6,21 @@ import ( "strconv" "time" - "github.com/bwmarrin/snowflake" - "baron-sso-backend/internal/handler" - "baron-sso-backend/internal/logger" - "baron-sso-backend/internal/repository" - - "github.com/gofiber/fiber/v2" + "github.com/bwmarrin/snowflake" + + "baron-sso-backend/internal/handler" + + "baron-sso-backend/internal/logger" + + "baron-sso-backend/internal/repository" + + "baron-sso-backend/internal/service" + + + + "github.com/gofiber/fiber/v2" + + "github.com/gofiber/fiber/v2/middleware/cors" "github.com/gofiber/fiber/v2/middleware/encryptcookie" "github.com/gofiber/fiber/v2/middleware/recover" @@ -58,9 +67,14 @@ func main() { slog.Warn("Failed to connect to ClickHouse. Audit logs will fail.", "error", err) } + redisService, err := service.NewRedisService() + if err != nil { + slog.Warn("Failed to connect to Redis. Auth features may fail.", "error", err) + } + // 2. Initialize Handlers auditHandler := handler.NewAuditHandler(auditRepo) - authHandler := handler.NewAuthHandler() + authHandler := handler.NewAuthHandler(redisService) adminHandler := handler.NewAdminHandler() // 3. Initialize Fiber @@ -118,7 +132,46 @@ func main() { }) app.Get("/health", func(c *fiber.Ctx) error { - return c.JSON(fiber.Map{"status": "ok"}) + status := "ok" + checks := make(map[string]string) + + // Check ClickHouse + if auditRepo != nil { + if err := auditRepo.Ping(c.Context()); err != nil { + checks["clickhouse"] = "error: " + err.Error() + status = "error" + } else { + checks["clickhouse"] = "ok" + } + } else { + checks["clickhouse"] = "not_initialized" + status = "degraded" + } + + // Check Redis + if redisService != nil { + if err := redisService.Ping(c.Context()); err != nil { + checks["redis"] = "error: " + err.Error() + status = "error" + } else { + checks["redis"] = "ok" + } + } else { + checks["redis"] = "not_initialized" + status = "degraded" + } + + if status == "error" { + return c.Status(fiber.StatusServiceUnavailable).JSON(fiber.Map{ + "status": status, + "checks": checks, + }) + } + + return c.JSON(fiber.Map{ + "status": status, + "checks": checks, + }) }) // API Group diff --git a/backend/internal/handler/auth_handler.go b/backend/internal/handler/auth_handler.go index 5b8700d2..df498cb9 100644 --- a/backend/internal/handler/auth_handler.go +++ b/backend/internal/handler/auth_handler.go @@ -49,16 +49,12 @@ func GenerateSecureToken(length int) string { return hex.EncodeToString(b) } -func NewAuthHandler() *AuthHandler { - redisService, err := service.NewRedisService() - if err != nil { - log.Fatalf("Failed to connect to Redis: %v", err) - } - +func NewAuthHandler(redisService *service.RedisService) *AuthHandler { projectID := os.Getenv("DESCOPE_PROJECT_ID") managementKey := os.Getenv("DESCOPE_MANAGEMENT_KEY") var descopeClient *client.DescopeClient + var err error if projectID != "" { descopeClient, err = client.NewWithConfig(&client.Config{ ProjectID: projectID, diff --git a/backend/internal/repository/clickhouse_repo.go b/backend/internal/repository/clickhouse_repo.go index e980259e..278a9d9d 100644 --- a/backend/internal/repository/clickhouse_repo.go +++ b/backend/internal/repository/clickhouse_repo.go @@ -79,3 +79,10 @@ func (r *ClickHouseRepository) Create(log *domain.AuditLog) error { log.Details, ) } + +func (r *ClickHouseRepository) Ping(ctx context.Context) error { + if r.conn == nil { + return fmt.Errorf("clickhouse connection is nil") + } + return r.conn.Ping(ctx) +} diff --git a/backend/internal/service/redis_service.go b/backend/internal/service/redis_service.go index 08e60a62..1686e5bb 100644 --- a/backend/internal/service/redis_service.go +++ b/backend/internal/service/redis_service.go @@ -33,6 +33,13 @@ func NewRedisService() (*RedisService, error) { return &RedisService{Client: rdb}, nil } +func (s *RedisService) Ping(ctx context.Context) error { + if s.Client == nil { + return os.ErrInvalid + } + return s.Client.Ping(ctx).Err() +} + // StoreVerificationCode saves the SMS verification code with a 3-minute expiration func (s *RedisService) StoreVerificationCode(phone, code string) error { // Key format: "sms_verify:01012345678" diff --git a/docker-compose.yaml b/docker-compose.yaml index 18eb507f..68328c1c 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,5 +1,3 @@ -version: "3.8" - services: backend: build: @@ -35,6 +33,13 @@ services: - ./backend:/app command: ["go", "run", "./cmd/server/main.go"] + healthcheck: + test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/health"] + interval: 10s + timeout: 5s + retries: 3 + start_period: 10s + frontend: build: context: ./frontend @@ -52,7 +57,8 @@ services: networks: - baron_net depends_on: - - backend + backend: + condition: service_healthy command: > /bin/sh -c "mkdir -p /usr/share/nginx/html/assets && echo \"DESCOPE_PROJECT_ID=$${DESCOPE_PROJECT_ID}\" > /usr/share/nginx/html/assets/.env && diff --git a/docker/docker-compose.deploy.yaml b/docker/docker-compose.deploy.yaml index 48b4671e..4544acfb 100644 --- a/docker/docker-compose.deploy.yaml +++ b/docker/docker-compose.deploy.yaml @@ -20,6 +20,12 @@ services: - "${BACKEND_PORT:-3000}:3000" depends_on: - infra_check + healthcheck: + test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/health"] + interval: 10s + timeout: 5s + retries: 3 + start_period: 10s networks: - baron_net @@ -30,7 +36,8 @@ services: ports: - "${FRONTEND_PORT:-80}:80" depends_on: - - backend + backend: + condition: service_healthy networks: - baron_net