Files
backend/cmd/api/main.go
2025-12-13 22:34:01 +05:00

126 lines
3.0 KiB
Go

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
}