// Package postgres é o adapter de saída para o PostgreSQL. package postgres import ( "context" "fmt" "log/slog" "time" "github.com/jackc/pgx/v5/pgxpool" "botpontos/internal/config" ) const ( connectAttempts = 10 connectDelay = 3 * time.Second ) // OpenPool abre o pool e espera o Postgres responder, com algumas tentativas // para tolerar a ordem de subida dos containers. func OpenPool(ctx context.Context, cfg config.DB, logger *slog.Logger) (*pgxpool.Pool, error) { poolCfg, err := pgxpool.ParseConfig(cfg.DSN()) if err != nil { return nil, fmt.Errorf("configuração do Postgres: %w", err) } poolCfg.MaxConns = cfg.MaxConns pool, err := pgxpool.NewWithConfig(ctx, poolCfg) if err != nil { return nil, fmt.Errorf("criar pool do Postgres: %w", err) } if err := waitFor(ctx, logger, pool.Ping); err != nil { pool.Close() return nil, err } return pool, nil } func waitFor(ctx context.Context, logger *slog.Logger, ping func(context.Context) error) error { var err error for attempt := 1; attempt <= connectAttempts; attempt++ { pingCtx, cancel := context.WithTimeout(ctx, 5*time.Second) err = ping(pingCtx) cancel() if err == nil { return nil } logger.Warn("Postgres indisponível; nova tentativa", "attempt", attempt, "error", err) select { case <-ctx.Done(): return ctx.Err() case <-time.After(connectDelay): } } return fmt.Errorf("conectar ao Postgres após %d tentativas: %w", connectAttempts, err) }