Documentation
¶
Overview ¶
Package sqlconn solves the boilerplate and lifecycle complexity of managing a database/sql connection in long-running Go services.
Problem ¶
Opening a SQL connection in production is more than calling sql.Open: services must apply pool limits, verify connectivity, expose health checks, and close the connection gracefully on shutdown signals. When every service reimplements this flow, behavior drifts and shutdown/health edge cases become hard to reason about.
sqlconn provides a small, configurable connection manager that standardizes this pattern.
How It Works ¶
- New creates a connection from explicit `driver` and `dsn` values.
- Connect accepts a URL-like string in the form `<DRIVER>://<DSN>` and delegates to New. If only the DSN is provided, a driver can be supplied via WithDefaultDriver.
- The context passed to New/Connect bounds connection establishment only (dialing and the initial health check). It does NOT control the pool lifetime: a request- or timeout-scoped context will not close the pool when it ends. To close the pool on application shutdown, wire a long-lived context via WithLifetimeContext and/or a shutdown channel via WithShutdownSignalChan, or call SQLConn.Shutdown directly.
- On successful connect, pool settings are applied (`max idle/open`, idle time, lifetime), and a goroutine waits for a shutdown signal channel, a canceled lifetime context, or a direct SQLConn.Shutdown call.
- When shutdown is triggered, SQLConn.Shutdown closes the underlying database handle, updates the shared shutdown wait group, and prevents further use by setting the internal DB pointer to nil. Shutdown is idempotent and also stops the watcher goroutine, so the watcher and a deferred call can both fire safely without leaking the goroutine.
Key Features ¶
- Configurable connection pipeline via options: WithConnectFunc, WithCheckConnectionFunc, WithSQLOpenFunc.
- Pool tuning support: WithConnMaxIdleCount, WithConnMaxIdleTime, WithConnMaxLifetime, WithConnMaxOpen.
- Built-in health check through SQLConn.HealthCheck, using a ping timeout (WithPingTimeout) and a basic validation query (`SELECT 1`).
- Graceful shutdown integration for application lifecycles with WithLifetimeContext, WithShutdownSignalChan and WithShutdownWaitGroup.
- Logger integration with WithLogger for lifecycle diagnostics.
Benefits ¶
- Consistent SQL connection behavior across services.
- Safer startup/shutdown handling with fewer resource-leak risks.
- Better testability through injectable open/connect/check functions.
- Clear integration points for health endpoints and service orchestration.
Usage ¶
Minimal: the deferred SQLConn.Shutdown closes the pool and stops the watcher. The context bounds establishment only, so it is safe to pass a short-lived one.
c, err := sqlconn.Connect(
ctx,
"mysql://user:pass@tcp(localhost:3306)/appdb",
sqlconn.WithDefaultDriver("mysql"),
)
if err != nil {
return err
}
if err := c.HealthCheck(ctx); err != nil {
return err
}
defer c.Shutdown(ctx)
Service lifecycle: wire the connection into a shared shutdown channel and wait group so a central signal closes every pool and the process waits for them.
c, err := sqlconn.Connect(
ctx,
"mysql://user:pass@tcp(localhost:3306)/appdb",
sqlconn.WithDefaultDriver("mysql"),
sqlconn.WithShutdownSignalChan(shutdownCh), // close(shutdownCh) closes the pool
sqlconn.WithShutdownWaitGroup(&shutdownWG), // shutdownWG.Wait() blocks until closed
)
if err != nil {
return err
}
This package is ideal for Go applications that need a pragmatic, reusable database/sql connection lifecycle abstraction with health and shutdown support.
Index ¶
- Variables
- type CheckConnectionFunc
- type ConnectFunc
- type Option
- func WithCheckConnectionFunc(fn CheckConnectionFunc) Option
- func WithConnMaxIdleCount(maxIdle int) Option
- func WithConnMaxIdleTime(t time.Duration) Option
- func WithConnMaxLifetime(t time.Duration) Option
- func WithConnMaxOpen(maxOpen int) Option
- func WithConnectFunc(fn ConnectFunc) Option
- func WithDefaultDriver(driver string) Option
- func WithLifetimeContext(ctx context.Context) Option
- func WithLogger(logger *slog.Logger) Option
- func WithPingTimeout(t time.Duration) Option
- func WithSQLOpenFunc(fn SQLOpenFunc) Option
- func WithShutdownSignalChan(ch chan struct{}) Option
- func WithShutdownWaitGroup(wg *sync.WaitGroup) Option
- func WithValidationQuery(query string) Option
- type SQLConn
- type SQLOpenFunc
Constants ¶
This section is empty.
Variables ¶
var ( // ErrDriverRequired is returned when no database driver is configured. ErrDriverRequired = errors.New("database driver must be set") // ErrDSNRequired is returned when no database DSN is configured. ErrDSNRequired = errors.New("database DSN must be set") // ErrNilConnectFunc is returned when the connect function is nil. ErrNilConnectFunc = errors.New("database connect function must be set") // ErrNilCheckConnectionFunc is returned when the check connection function is nil. ErrNilCheckConnectionFunc = errors.New("check connection function must be set") // ErrNilSQLOpenFunc is returned when the sql open function is nil. ErrNilSQLOpenFunc = errors.New("sql open function must be set") // ErrInvalidMaxIdleCount is returned when the pool max idle connection count is negative. ErrInvalidMaxIdleCount = errors.New("database pool max idle connections must not be negative") // ErrInvalidMaxIdleTime is returned when the connection max idle time is negative. ErrInvalidMaxIdleTime = errors.New("database connection max idle time must not be negative") // ErrInvalidMaxLifetime is returned when the connection max lifetime is negative. ErrInvalidMaxLifetime = errors.New("database connection max lifetime must not be negative") // ErrInvalidMaxOpenCount is returned when the pool max open connection count is negative. ErrInvalidMaxOpenCount = errors.New("database pool max open connections must not be negative") // ErrInvalidPingTimeout is returned when the ping timeout is below one second. ErrInvalidPingTimeout = errors.New("database ping timeout must be at least 1 second") // ErrNilLogger is returned when the logger is nil. ErrNilLogger = errors.New("logger is required") // ErrNilShutdownWaitGroup is returned when the shutdown wait group is nil. ErrNilShutdownWaitGroup = errors.New("shutdownWaitGroup is required") // ErrNilShutdownSignalChan is returned when the shutdown signal channel is nil. ErrNilShutdownSignalChan = errors.New("shutdownSignalChan is required") // ErrEmptyValidationQuery is returned when the health-check validation query is blank. ErrEmptyValidationQuery = errors.New("validation query must not be empty") )
Exported sentinel errors returned by configuration validation and health checks so callers can match them with errors.Is.
var ( // ErrNilContext is returned by [New]/[Connect] when the provided context is nil. ErrNilContext = errors.New("context is required") // ErrNilDB is returned when the configured connect (or sql open) function // yields a nil database handle without an error. ErrNilDB = errors.New("connect or sql open function returned a nil database handle") // already been shut down. Callers can match it with errors.Is to distinguish a // shut-down pool from a genuine connectivity failure. ErrUnavailable = errors.New("database is unavailable") )
Exported sentinel errors returned by connection setup and health checks so callers can match them with errors.Is.
Functions ¶
This section is empty.
Types ¶
type CheckConnectionFunc ¶
CheckConnectionFunc is the type of function called to perform a DB connection check.
type ConnectFunc ¶
ConnectFunc is the type of function called to perform the actual DB connection.
type Option ¶
type Option func(*config)
Option configures SQL connection behavior.
func WithCheckConnectionFunc ¶
func WithCheckConnectionFunc(fn CheckConnectionFunc) Option
WithCheckConnectionFunc replaces default connection verification function. To change only the validation query of the built-in check (rather than replace the whole check), use WithValidationQuery instead.
func WithConnMaxIdleCount ¶
WithConnMaxIdleCount sets the maximum number of idle database connections in the pool. Zero disables the idle connection pool. When greater than the max open count, database/sql silently caps it to the max open count.
func WithConnMaxIdleTime ¶
WithConnMaxIdleTime sets the maximum time a connection may remain idle before being closed. Zero means connections are never closed due to idle time.
func WithConnMaxLifetime ¶
WithConnMaxLifetime sets the maximum time a connection may be reused before being closed. Zero means connections are never closed due to their age.
func WithConnMaxOpen ¶
WithConnMaxOpen sets the maximum number of open connections in the pool. Zero means there is no limit on the number of open connections.
func WithConnectFunc ¶
func WithConnectFunc(fn ConnectFunc) Option
WithConnectFunc replaces default connection function (e.g., for testing). The connection manager applies the pool settings (max idle/open, idle time, lifetime) to the returned handle after this function returns, so those limits take precedence over any pool tuning the custom function applied itself.
func WithDefaultDriver ¶
WithDefaultDriver sets fallback driver if not included in DSN.
func WithLifetimeContext ¶
WithLifetimeContext sets the context whose cancellation triggers a graceful shutdown of the connection. It is independent from the context passed to New/Connect, which bounds only connection establishment (dialing and the initial health check). When unset, the connection lifetime is governed solely by the shutdown signal channel (WithShutdownSignalChan) and explicit Shutdown calls, and a short-lived establishment context cannot tear the pool down.
func WithLogger ¶
WithLogger overrides default logger for connection lifecycle events.
func WithPingTimeout ¶
WithPingTimeout sets context timeout for health check ping operations.
func WithSQLOpenFunc ¶
func WithSQLOpenFunc(fn SQLOpenFunc) Option
WithSQLOpenFunc replaces default sql.Open wrapper (for testing only).
func WithShutdownSignalChan ¶
func WithShutdownSignalChan(ch chan struct{}) Option
WithShutdownSignalChan sets channel to trigger graceful shutdown of connection.
func WithShutdownWaitGroup ¶
WithShutdownWaitGroup sets external wait group to signal when connection closes.
func WithValidationQuery ¶
WithValidationQuery overrides the query the built-in health check runs after the ping (default "SELECT 1"). Use it for engines where "SELECT 1" is invalid, e.g. Oracle requires "SELECT 1 FROM DUAL". The query must return at least one row with a single scannable column. It has no effect when the whole check is replaced via WithCheckConnectionFunc.
type SQLConn ¶
type SQLConn struct {
// contains filtered or unexported fields
}
SQLConn is the structure that helps to manage a SQL DB connection.
func Connect ¶
Connect parses URL format "<DRIVER>://<DSN>" and delegates to New for connection creation.
func New ¶
New constructs a SQL connection with pool tuning, health checks, and graceful shutdown orchestration. The provided context bounds connection establishment only; use WithLifetimeContext and/or WithShutdownSignalChan to control the pool lifetime.
func (*SQLConn) HealthCheck ¶
HealthCheck verifies database connectivity with a ping and validation query, respecting the configured ping timeout. It returns ErrUnavailable when the connection has already been shut down.
The read lock is intentionally held for the full ping+query round-trip so the underlying handle cannot be closed by a concurrent Shutdown mid-check; a Shutdown may therefore block for up to the ping timeout behind an in-flight health check.
func (*SQLConn) Shutdown ¶
Shutdown gracefully closes database connection, preventing new queries and updating shutdown wait group. The context parameter is intentionally ignored: sql.DB.Close takes no context. Shutdown is idempotent; calling it more than once is a no-op and never drives the wait group negative.