panel public release
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
// Package db owns the Controller's durable state in Postgres. It exposes
|
||||
// a small typed surface (UpsertAgent, InsertInstance, ListInstances, …)
|
||||
// built on pgx/v5 with a connection pool. Migrations are embedded so the
|
||||
// binary is self-contained.
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
// DB wraps a pgx pool with our typed query methods.
|
||||
type DB struct {
|
||||
pool *pgxpool.Pool
|
||||
}
|
||||
|
||||
// Open connects to Postgres using dsn, pings once to fail fast on bad
|
||||
// credentials or unreachable server, and runs any pending migrations.
|
||||
func Open(ctx context.Context, dsn string) (*DB, error) {
|
||||
cfg, err := pgxpool.ParseConfig(dsn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse db dsn: %w", err)
|
||||
}
|
||||
cfg.MaxConns = 10
|
||||
cfg.MaxConnLifetime = 30 * time.Minute
|
||||
|
||||
pool, err := pgxpool.NewWithConfig(ctx, cfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("new pool: %w", err)
|
||||
}
|
||||
|
||||
pingCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
if err := pool.Ping(pingCtx); err != nil {
|
||||
pool.Close()
|
||||
return nil, fmt.Errorf("ping db: %w", err)
|
||||
}
|
||||
|
||||
if err := Migrate(ctx, pool); err != nil {
|
||||
pool.Close()
|
||||
return nil, fmt.Errorf("migrate: %w", err)
|
||||
}
|
||||
|
||||
return &DB{pool: pool}, nil
|
||||
}
|
||||
|
||||
// Close releases pool resources.
|
||||
func (db *DB) Close() {
|
||||
if db != nil && db.pool != nil {
|
||||
db.pool.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// Pool exposes the underlying pool for tests / advanced callers.
|
||||
func (db *DB) Pool() *pgxpool.Pool { return db.pool }
|
||||
Reference in New Issue
Block a user