package main import ( "context" "fmt" "log" "net/http" "os" "os/signal" "syscall" "time" "git.kirlllll.ru/volontery/backend/internal/api" "git.kirlllll.ru/volontery/backend/internal/config" "git.kirlllll.ru/volontery/backend/internal/pkg/jwt" "git.kirlllll.ru/volontery/backend/internal/repository" "git.kirlllll.ru/volontery/backend/internal/service" ) func main() { if err := run(); err != nil { log.Fatal(err) } } func run() error { // Загрузка конфигурации cfg, err := config.Load() if err != nil { return fmt.Errorf("failed to load config: %w", err) } log.Printf("Starting server in %s mode", cfg.AppEnv) // Подключение к базе данных ctx := context.Background() pool, err := config.NewDBPool(ctx, cfg.DatabaseURL) if err != nil { return fmt.Errorf("failed to connect to database: %w", err) } defer pool.Close() log.Println("Connected to database") // Инициализация репозиториев repos := repository.New(pool) // Инициализация JWT менеджера jwtManager := jwt.NewManager( cfg.JWTSecret, cfg.JWTAccessTokenTTL, cfg.JWTRefreshTokenTTL, ) // Инициализация сервисов authService := service.NewAuthService( repos.User, repos.Auth, repos.RBAC, jwtManager, ) userService := service.NewUserService( repos.User, repos.RBAC, ) requestService := service.NewRequestService( repos.Request, ) // Создание HTTP сервера server := api.NewServer( cfg, authService, userService, requestService, jwtManager, ) // Настройка HTTP сервера addr := fmt.Sprintf("%s:%s", cfg.ServerHost, cfg.ServerPort) httpServer := &http.Server{ Addr: addr, Handler: server, ReadTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second, IdleTimeout: 60 * time.Second, } // Канал для обработки ошибок сервера serverErrors := make(chan error, 1) // Запуск HTTP сервера в горутине go func() { log.Printf("Server listening on %s", addr) serverErrors <- httpServer.ListenAndServe() }() // Канал для обработки сигналов завершения shutdown := make(chan os.Signal, 1) signal.Notify(shutdown, os.Interrupt, syscall.SIGTERM) // Блокируемся до получения сигнала завершения или ошибки сервера select { case err := <-serverErrors: return fmt.Errorf("server error: %w", err) case sig := <-shutdown: log.Printf("Received signal %v, starting graceful shutdown", sig) // Даем 30 секунд на завершение активных запросов ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() if err := httpServer.Shutdown(ctx); err != nil { httpServer.Close() return fmt.Errorf("failed to gracefully shutdown server: %w", err) } log.Println("Server stopped gracefully") } return nil }