All checks were successful
Dev Build / build-test (pull_request) Successful in 2m6s
63 lines
1.4 KiB
Go
63 lines
1.4 KiB
Go
// Package db provides PostgreSQL connection management using pgx.
|
|
package db
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log/slog"
|
|
"time"
|
|
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
// Pool wraps a pgx connection pool with lifecycle helpers.
|
|
type Pool struct {
|
|
*pgxpool.Pool
|
|
}
|
|
|
|
// New creates a connection pool from a PostgreSQL DSN.
|
|
func New(dsn string) (*Pool, error) {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
cfg, err := pgxpool.ParseConfig(dsn)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("parse pgx config: %w", err)
|
|
}
|
|
|
|
// Sensible defaults
|
|
cfg.MaxConns = 20
|
|
cfg.MinConns = 2
|
|
cfg.MaxConnLifetime = 30 * time.Minute
|
|
cfg.MaxConnIdleTime = 10 * time.Minute
|
|
cfg.HealthCheckPeriod = 5 * time.Second
|
|
|
|
pool, err := pgxpool.NewWithConfig(ctx, cfg)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("create pgx pool: %w", err)
|
|
}
|
|
|
|
if err := pool.Ping(ctx); err != nil {
|
|
pool.Close()
|
|
return nil, fmt.Errorf("ping database: %w", err)
|
|
}
|
|
|
|
slog.Info("database connected", "pool", cfg.ConnConfig.Database)
|
|
return &Pool{Pool: pool}, nil
|
|
}
|
|
|
|
// Close shuts down the pool gracefully.
|
|
func (p *Pool) Close() {
|
|
if p.Pool != nil {
|
|
p.Pool.Close()
|
|
slog.Info("database pool closed")
|
|
}
|
|
}
|
|
|
|
// Health returns nil if the database is reachable.
|
|
func (p *Pool) Health(ctx context.Context) error {
|
|
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
|
|
defer cancel()
|
|
return p.Ping(ctx)
|
|
}
|