package internal import ( "context" "database/sql" "fmt" "time" "github.com/kelseyhightower/envconfig" "github.com/uptrace/bun/driver/pgdriver" "github.com/uptrace/bun" "github.com/uptrace/bun/dialect/pgdialect" ) const ( dbPingTimeout = 10 * time.Second ) type bunConfig struct { DSN string `envconfig:"DSN" required:"true"` MaxOpenConnections int `envconfig:"MAX_OPEN_CONNECTIONS" default:"5"` MaxIdleConnections int `envconfig:"MAX_IDLE_CONNECTIONS" default:"2"` ConnectionMaxLifetime time.Duration `envconfig:"CONNECTION_MAX_LIFETIME" default:"3m"` } func NewBunDB() (*bun.DB, error) { var cfg bunConfig if err := envconfig.Process("DB", &cfg); err != nil { return nil, fmt.Errorf("envconfig.Process: %w", err) } db := bun.NewDB(newSQLDB(cfg), pgdialect.New()) ctx, cancel := context.WithTimeout(context.Background(), dbPingTimeout) defer cancel() if err := db.PingContext(ctx); err != nil { return nil, fmt.Errorf("db.PingContext: %w", err) } return db, nil } func newSQLDB(cfg bunConfig) *sql.DB { db := sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN(cfg.DSN))) db.SetMaxOpenConns(cfg.MaxOpenConnections) db.SetMaxIdleConns(cfg.MaxIdleConnections) db.SetConnMaxLifetime(cfg.ConnectionMaxLifetime) return db }