package app import ( "context" "errors" "github.com/themakers/hlog" "go.uber.org/zap" "heruvym/app" "heruvym/internal/initialize" "heruvym/pkg/closer" "strconv" "time" ) var zapOptions = []zap.Option{ zap.AddCaller(), zap.AddCallerSkip(2), zap.AddStacktrace(zap.ErrorLevel), } type Build struct { Commit string Version string BuildTime int64 } func Run(ctx context.Context, cfg initialize.Config, build Build) error { var logger *zap.Logger var err error if cfg.LoggerDevMode { logger, err = zap.NewProduction(zapOptions...) if err != nil { return err } } else { logger, err = zap.NewDevelopment(zapOptions...) if err != nil { return err } } logger = logger.With( zap.String("SvcCommit", build.Commit), zap.String("SvcVersion", build.Version), zap.String("SvcBuildTime", strconv.FormatInt(build.BuildTime, 10)), ) hlogger := hlog.New(logger) hlogger.Emit(app.InfoSvcStarted{}) 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() mdb, err := initialize.MongoDB(ctx, cfg) if err != nil { logger.Error("Error initializing MongoDB", zap.Error(err)) return err } minioClient, err := initialize.Minio(ctx, cfg) if err != nil { logger.Error("Error initializing Minio", zap.Error(err)) return err } redisClient, err := initialize.Redis(ctx, cfg) if err != nil { logger.Error("Error initializing Redis", zap.Error(err)) return err } tgBot, err := initialize.NewTgBot(cfg) if err != nil { logger.Error("Error initializing Telegram", zap.Error(err)) return err } //shutdownGroup.Add(closer.CloserFunc(clientServer.Shutdown)) //shutdownGroup.Add(closer.CloserFunc(adminServer.Shutdown)) //shutdownGroup.Add(closer.CloserFunc(grpcServer.Stop)) //shutdownGroup.Add(closer.CloserFunc(mdb.Client().Disconnect)) //shutdownGroup.Add(closer.CloserFunc(recoveryWC.Stop)) //shutdownGroup.Add(closer.CloserFunc(purgeWC.Stop)) <-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 }