package app import ( "context" "errors" "gitea.pena/SQuiz/shutterstock/internal/client" "gitea.pena/SQuiz/shutterstock/internal/controller" "gitea.pena/SQuiz/shutterstock/internal/initialize" "gitea.pena/SQuiz/shutterstock/internal/server/http" "gitea.pena/SQuiz/shutterstock/pkg/closer" "go.uber.org/zap" "time" ) func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger) error { defer func() { if r := recover(); r != nil { logger.Error("Recovered from a panic", zap.Any("error", r)) } }() ctx, cancel := context.WithCancel(ctx) defer cancel() shutdownGroup := closer.NewCloserGroup() shutterStockClient := client.NewShutterStockClient(client.Deps{ ShutterStockApiToken: cfg.ShutterStockAPIToken, ShutterStockUrl: cfg.ShutterStockAPIUrl, Logger: logger, }) shutterStockController := controller.NewShutterStockController(shutterStockClient) srv := http.NewServer(http.ServerConfig{ Logger: logger, Controllers: []http.Controller{shutterStockController}, }) go func() { if err := srv.Start(cfg.ClientHttpURL); err != nil { logger.Error("Server startup error", zap.Error(err)) cancel() } }() srv.ListRoutes() shutdownGroup.Add(closer.CloserFunc(srv.Shutdown)) <-ctx.Done() timeoutCtx, timeoutCancel := context.WithTimeout(context.Background(), 10*time.Second) defer timeoutCancel() if err := shutdownGroup.Call(timeoutCtx); err != nil { if errors.Is(err, context.DeadlineExceeded) { logger.Error("Shutdown timed out", zap.Error(err)) } else { logger.Error("Failed to shutdown services gracefully", zap.Error(err)) } return err } logger.Info("Application has stopped") return nil }