Documentation
¶
Overview ¶
Package postgres provides an instrumented PostgreSQL client backed by a pgxpool.Pool that implements app.Component.
Two access paths are exposed after Client.Start:
Client.DB returns a standard *sql.DB derived from the pool. Use this for standard queries and full compatibility with ORMs (sqlx, GORM, Bun), query builders, and migration frameworks (golang-migrate, goose).
Client.Pool returns the underlying *pgxpool.Pool for pgx-native operations: COPY FROM/TO for bulk loads, batch queries, named prepared statements, and LISTEN/NOTIFY for pub-sub patterns.
Both paths share the same connection pool and query tracer, so OpenTelemetry spans are recorded regardless of which path is used.
Basic usage ¶
client, err := postgres.New("postgres://user:pass@localhost:5432/mydb")
if err != nil { log.Fatal(err) }
a.Register(client)
if err := a.Start(ctx); err != nil { log.Fatal(err) }
defer a.Shutdown(ctx)
// Standard database/sql path — compatible with ORMs and migrations.
rows, err := client.DB().QueryContext(ctx, "SELECT id FROM users WHERE active = $1", true)
// pgx-native path — for COPY, batching, LISTEN/NOTIFY.
batch := &pgx.Batch{}
batch.Queue("INSERT INTO events (name) VALUES ($1)", "signup")
results := client.Pool().SendBatch(ctx, batch)
With tracing ¶
client, err := postgres.NewWithConfig(&postgres.Config{
DSN: "postgres://user:pass@localhost:5432/mydb",
Tracer: a.Tracer(),
})
Every query automatically receives an OpenTelemetry span named after the SQL verb (e.g. "db SELECT", "db INSERT"). The full statement is recorded as the db.statement attribute and errors are recorded on the span.
PgBouncer ¶
The client defaults to pgx.QueryExecModeSimpleProtocol, which avoids server-side prepared statements and is compatible with PgBouncer in transaction-pooling mode (the standard deployment at GitLab.com). No additional configuration is required for PgBouncer compatibility.
When running behind PgBouncer, also set ConnMaxLifetime and ConnMaxIdleTime to recycle stale connections:
client, err := postgres.NewWithConfig(&postgres.Config{
DSN: "postgres://user:pass@pgbouncer:6432/mydb",
ConnMaxLifetime: 5 * time.Minute,
ConnMaxIdleTime: 60 * time.Second,
})
When connecting directly to PostgreSQL without a pooler, you can opt into cached prepared statements for better performance:
client, err := postgres.NewWithConfig(&postgres.Config{
DSN: "postgres://user:pass@localhost:5432/mydb",
QueryExecMode: pgx.QueryExecModeCacheStatement,
})
Example ¶
Example shows an instrumented PostgreSQL client registered as an app component. Start creates the pool and pings the server; Shutdown closes all connections cleanly.
package main
import (
"context"
"gitlab.com/gitlab-org/labkit/v2/postgres"
)
func main() {
ctx := context.Background()
db, err := postgres.NewWithConfig(&postgres.Config{
DSN: "postgres://user:pass@localhost:5432/mydb",
// Tracer: a.Tracer(),
})
if err != nil {
// DSN parse errors are caught here before Start is called.
panic(err)
}
// Register with app.App so the lifecycle is managed automatically:
// a.Register(db)
// a.Run(ctx)
//
// Or manage manually:
if err := db.Start(ctx); err != nil {
panic(err)
}
defer db.Shutdown(ctx)
// DB() returns *sql.DB — compatible with ORMs, query builders, migrations.
row := db.DB().QueryRowContext(ctx, "SELECT version()")
var version string
_ = row.Scan(&version)
// Pool() returns *pgxpool.Pool — for COPY, batching, LISTEN/NOTIFY.
_ = db.Pool()
}
Output:
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is an instrumented PostgreSQL client backed by a pgxpool.Pool that implements app.Component. Call [Start] to open the pool and [Shutdown] to close it.
Client.DB returns a standard *sql.DB derived from the pool, compatible with ORMs, query builders, and migration frameworks. Client.Pool returns the underlying *pgxpool.Pool for pgx-native operations such as COPY, batch queries, and LISTEN/NOTIFY.
func New ¶
New returns a Client for the given DSN with no tracing. It is shorthand for NewWithConfig(&Config{DSN: dsn}).
func NewWithConfig ¶
NewWithConfig returns a Client configured with cfg. DSN parsing is performed eagerly so that configuration errors are caught before Start is called.
Example ¶
ExampleNewWithConfig shows connection pool tuning for services running behind PgBouncer, where long-lived connections should be recycled.
package main
import (
"time"
"gitlab.com/gitlab-org/labkit/v2/postgres"
)
func main() {
db, err := postgres.NewWithConfig(&postgres.Config{
DSN: "postgres://user:pass@pgbouncer:6432/mydb",
Name: "primary",
MaxConns: 20,
MinConns: 2, // keep 2 connections warm
ConnMaxLifetime: 5 * time.Minute,
ConnMaxIdleTime: 60 * time.Second,
})
if err != nil {
panic(err)
}
_ = db
}
Output:
func (*Client) DB ¶
DB returns the standard *sql.DB derived from the pool. Compatible with ORMs, query builders, and migration frameworks. Returns nil before [Start] has been called successfully.
func (*Client) Pool ¶
Pool returns the underlying *pgxpool.Pool for pgx-native operations. Use this for bulk loads ([COPY FROM / COPY TO]), batch queries, named prepared statements, and LISTEN/NOTIFY. Returns nil before [Start] has been called successfully.
func (*Client) QueryExecMode ¶
func (c *Client) QueryExecMode() pgx.QueryExecMode
QueryExecMode returns the pgx.QueryExecMode that will be used for queries. The default is pgx.QueryExecModeSimpleProtocol for PgBouncer compatibility.
func (*Client) QueryTracer ¶
func (c *Client) QueryTracer() pgx.QueryTracer
QueryTracer returns the pgx.QueryTracer configured on this client, or nil when no [Config.Tracer] was provided. This is primarily useful for testing the tracing integration without a live database.
func (*Client) Shutdown ¶
Shutdown closes the sql.DB and the underlying pool, releasing all connections. It satisfies app.Component and should be called via app.App.Shutdown.
func (*Client) Start ¶
Start creates the connection pool and verifies connectivity with a ping. It satisfies app.Component and should be called via app.App.Start.
type Config ¶
type Config struct {
// DSN is the PostgreSQL connection string.
// Accepts postgres:// and postgresql:// URL formats, as well as key=value
// connection strings (e.g. "host=localhost user=postgres dbname=mydb").
DSN string
// Name identifies this client in logs and errors. Defaults to "postgres".
// Use distinct names when a service connects to multiple databases.
Name string
// MaxConns is the maximum number of connections in the pool.
// Maps to pgxpool.Config.MaxConns. Zero uses the pgxpool default
// (max(4, runtime.NumCPU())).
MaxConns int
// MinConns is the minimum number of connections to keep open in the pool,
// even when idle. Maps to pgxpool.Config.MinConns. Zero means no minimum.
// Use this to pre-warm connections at startup and avoid cold-start latency
// on the first requests.
MinConns int
// MaxIdleConns is not used by the pgxpool backend and has no effect.
// To keep a minimum number of connections warm, use [Config.MinConns].
// To close connections that have been idle too long, use [Config.ConnMaxIdleTime].
//
// Deprecated: retained for source compatibility; has no effect.
MaxIdleConns int
// ConnMaxLifetime is the maximum duration a connection may be reused.
// Maps to pgxpool.Config.MaxConnLifetime. Zero means no age limit.
// Set this when using PgBouncer or similar connection poolers to ensure
// stale connections are recycled.
ConnMaxLifetime time.Duration
// ConnMaxIdleTime is the maximum duration a connection may sit idle
// before being closed. Maps to pgxpool.Config.MaxConnIdleTime.
// Zero means connections are not closed due to idle time.
ConnMaxIdleTime time.Duration
// QueryExecMode controls how pgx executes queries. Defaults to
// [pgx.QueryExecModeSimpleProtocol], which avoids server-side prepared
// statements and is required for PgBouncer in transaction-pooling mode
// (the standard deployment at GitLab.com).
//
// Set to [pgx.QueryExecModeCacheStatement] or another mode only when
// connecting directly to PostgreSQL without a connection pooler.
//
// See https://pkg.go.dev/github.com/jackc/pgx/v5#QueryExecMode for all
// available modes.
QueryExecMode pgx.QueryExecMode
// Tracer is used to create spans for queries. When nil, tracing is
// disabled.
Tracer *trace.Tracer
}
Config holds optional configuration for New / NewWithConfig.