package main import ( "context" "log" "log/slog" "net/http" "os" "os/signal" "syscall" "time" "nfeeder/internal/db" "nfeeder/internal/web" "github.com/jackc/pgx/v5/pgxpool" ) func main() { // @Logger // ------------------------------------------------------------ var handler slog.Handler if os.Getenv("ENV") == "production" { handler = slog.NewJSONHandler(os.Stdout, nil) } else { handler = slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug}) } logger := slog.New(handler) ctx, ctxCancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) defer ctxCancel() // @DB // ------------------------------------------------------------ connStr := os.Getenv("DATABASE_URL") if connStr == "" { log.Fatal("DATABASE_URL environment variable is not set") } poolConfig, err := pgxpool.ParseConfig(connStr) if err != nil { log.Fatalf("Unable to parse DATABASE_URL: %v", err) } poolConfig.MaxConns = 25 poolConfig.MinConns = 5 poolConfig.MaxConnLifetime = 5 * time.Minute poolConfig.MaxConnIdleTime = 30 * time.Second pool, err := pgxpool.NewWithConfig(ctx, poolConfig) if err != nil { log.Fatalf("Unable to create connection pool: %v", err) } // Verify the connection is alive before proceeding if err := pool.Ping(ctx); err != nil { log.Fatalf("Unable to reach database: %v", err) } logger.Info("database connection established", "max_conns", poolConfig.MaxConns, "min_conns", poolConfig.MinConns) defer func() { pool.Close() logger.Info("database pool closed") }() // Create Store sqlc wrapper store := db.NewStore(pool) // @Server // ------------------------------------------------------------ jwtSecret := os.Getenv("JWT_SECRET") if jwtSecret == "" { log.Fatal("JWT_SECRET environment variable is required") } server := web.NewServer(store, logger, jwtSecret) // We run it in a goroutine so it doesn't block main from reaching the signal listener. go func() { addr := os.Getenv("SERVER_PORT") if connStr == "" { log.Fatal("SERVER_PORT environment variable is not set") } if err := server.Start(addr); err != nil && err != http.ErrServerClosed { log.Fatalf("Server failed: %v", err) } }() // @GracefulShutdown // ------------------------------------------------------------ <-ctx.Done() logger.Warn("shutdown signal received", "signal", "SIGTERM/Interrupt") shutdownCtx, shutdownCtxCancel := context.WithTimeout(context.Background(), 10*time.Second) defer shutdownCtxCancel() if err := server.Shutdown(shutdownCtx); err != nil { log.Fatalf("Graceful shutdown failed: %v", err) } logger.Info("Server shutdown successful") }