package main import ( "context" "fmt" "log/slog" "net/http" "os" "os/signal" "syscall" "time" "git-molva.ru/Molva/molva-backend/services/api_gateway/internal/logger" "git-molva.ru/Molva/molva-backend/services/api_gateway/internal/constants" "git-molva.ru/Molva/molva-backend/services/api_gateway/internal/broker" "git-molva.ru/Molva/molva-backend/services/api_gateway/internal/config" httprouter "git-molva.ru/Molva/molva-backend/services/api_gateway/internal/http" ) var ( version string commit string date string ) func main() { cfg := config.MustLoad(version, commit, date) log, err := logger.New(cfg.Env) if err != nil { panic(err) } log.Info("Starting App", slog.String("version", version), slog.String("commit", commit), slog.String("build_date", date)) log.Info("--------------------- CONFIG ---------------------") log.Info(fmt.Sprintf("Environment: %v", cfg)) brok := setupBroker(log, &cfg.Broker) defer func(brok *broker.RabbitMQBroker) { if err := brok.Disconnect(); err != nil { log.Error("Error disconnecting from broker") } }(brok) server, err := setupServer(log, cfg) if err != nil { panic(fmt.Sprintf("can not start http server: %v", err)) } serverErrors := make(chan error, 1) go func() { log.Info("starting server", slog.Int("port", cfg.Port)) serverErrors <- server.ListenAndServe() }() shutdownSignal := make(chan os.Signal, 1) signal.Notify(shutdownSignal, os.Interrupt, syscall.SIGTERM) select { case err := <-serverErrors: log.Error("Error starting server: %v\n", slog.Any("err", err)) case sig := <-shutdownSignal: log.Info("received signal. shutting down server", slog.String("signal", sig.String())) } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() log.Info("shutting down server...") if err := server.Shutdown(ctx); err != nil { log.Error(fmt.Sprintf("Error shutting down server: %v\n", err)) } log.Info("server gracefully stopped") } func setupServer(logger *slog.Logger, cfg *config.Config) (*http.Server, error) { router, err := httprouter.New(logger, cfg) if err != nil { return nil, err } httprouter.SetupRouter(router, cfg.Build) return &http.Server{ Addr: fmt.Sprintf("%s:%d", cfg.Host, cfg.Port), Handler: router.Mux, ReadHeaderTimeout: 15 * time.Second, }, nil } func doWithRetry(function func() error, serviceName string, logger *slog.Logger) { if err := function(); err != nil { logger.Error(fmt.Sprintf("Error connecting to %s: %v", serviceName, err), slog.String("error", err.Error())) go func() { ticker := time.NewTicker(constants.DefaultRetryTimeout) defer ticker.Stop() for range ticker.C { if err := function(); err != nil { logger.Error(fmt.Sprintf("Error connecting to %s: %v", serviceName, err), slog.String("error", err.Error())) } else { logger.Info(fmt.Sprintf("Successfully connected to %s service", serviceName)) break } } }() } else { logger.Info(fmt.Sprintf("Successfully connected to %s service", serviceName)) } } func setupBroker(logger *slog.Logger, cfg *config.Broker) *broker.RabbitMQBroker { brok := broker.NewRabbitMQBroker(cfg) doWithRetry(func() error { return brok.Connect() }, "Broker", logger) return brok }