package app import ( "context" "database/sql" "fmt" "log" "os" "os/signal" "syscall" "time" _ "github.com/jackc/pgx/v5/stdlib" "github.com/joho/godotenv" ) func initApp() (*App, func(), error) { _ = godotenv.Load() cfg, err := loadConfig() if err != nil { return nil, nil, fmt.Errorf("config error: %w", err) } db, err := sql.Open("pgx", cfg.DatabaseURL) if err != nil { return nil, nil, fmt.Errorf("database open error: %w", err) } cleanup := func() { _ = db.Close() } if err := db.Ping(); err != nil { cleanup() return nil, nil, fmt.Errorf("database ping error: %w", err) } a := &App{cfg: cfg, db: db} if err := a.migrate(context.Background()); err != nil { cleanup() return nil, nil, fmt.Errorf("migration error: %w", err) } return a, cleanup, nil } func Run() error { app, cleanup, err := initApp() if err != nil { return err } defer cleanup() handler := app.routes() servers, sockCleanup, err := startServers(app.cfg, handler) if err != nil { return fmt.Errorf("server start error: %w", err) } defer sockCleanup() log.Printf("server started: tcp=%q unix=%q dev_mode=%t", app.cfg.ListenAddr, app.cfg.UnixSocketPath, app.cfg.DevMode) sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM) <-sigCh ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() for _, s := range servers { if err := s.Shutdown(ctx); err != nil { log.Printf("shutdown error: %v", err) } } log.Printf("shutdown complete") return nil }