package app import ( "amocrm/internal/controllers" "amocrm/internal/initialize" "amocrm/internal/repository" "amocrm/internal/server/http" "amocrm/internal/service" "amocrm/pkg/closer" "context" "errors" "time" "go.uber.org/zap" ) func Run(ctx context.Context, config initialize.Config, logger *zap.Logger) error { defer func() { if r := recover(); r != nil { logger.Error("Recovered from a panic", zap.Any("error", r)) } }() logger.Info("App started", zap.Any("config", config)) ctx, cancel := context.WithCancel(ctx) defer cancel() shutdownGroup := closer.NewCloserGroup() mdb, err := initialize.MongoDB(ctx, config) if err != nil { logger.Error("failed initialize mongo") return err } repo := repository.NewRepository(repository.Deps{ MdbUser: mdb.Collection("amoUsers"), }) svc := service.NewService(service.Deps{ Repository: repo, Logger: logger, ConnectLink: config.ConnectLink, }) controller := controllers.NewController(controllers.Deps{ Service: svc, Logger: logger, }) server := http.NewServer(http.ServerConfig{ Controllers: []http.Controller{ controller, }, }) go func() { if err := server.Start(config.HTTPHost + ":" + config.HTTPPort); err != nil { logger.Error("Server startup error", zap.Error(err)) cancel() } }() server.ListRoutes() shutdownGroup.Add(closer.CloserFunc(server.Shutdown)) shutdownGroup.Add(closer.CloserFunc(mdb.Client().Disconnect)) <-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 }