Documentation
¶
Overview ¶
Package pgcluster connects to a PostgreSQL cluster over database/sql.
It keeps a pool per node and decides which one a query should use: the writer is discovered at runtime (by DNS, by pg_is_in_recovery(), or by probing for a writable transaction) so a failover does not need a restart, and reads are balanced across the healthy nodes. Failing nodes are dropped and retried, and a circuit breaker gives up quickly once the whole cluster is unreachable.
It returns *sql.DB, so an ORM binds to it in a few lines rather than being a dependency of this package.
Index ¶
- Constants
- type ClusterConfig
- type ClusterManager
- func (cm *ClusterManager) Close() error
- func (cm *ClusterManager) DB(ctx context.Context) (*sql.DB, error)
- func (cm *ClusterManager) ForceWriterDetection()
- func (cm *ClusterManager) GetNodeStats() map[string]NodeStats
- func (cm *ClusterManager) HealthCheck() error
- func (cm *ClusterManager) Reader() (*sql.DB, error)
- func (cm *ClusterManager) SetWriterNode(nodeName string) error
- func (cm *ClusterManager) WithReader(ctx context.Context) context.Context
- func (cm *ClusterManager) WithWriter(ctx context.Context) context.Context
- func (cm *ClusterManager) Writer() (*sql.DB, error)
- type DatabaseNode
- type NodeHealth
- type NodeRole
- type NodeStats
- type TombManager
- type WriterDetectionStrategy
Constants ¶
const CloudRDSExample = `` /* 514-byte string literal not displayed */
Query-Based Detection (Cloud RDS/Aurora)
const DefaultDriverName = "pgx"
DefaultDriverName is the database/sql driver used when ClusterConfig leaves DriverName empty. The package imports the pgx stdlib driver to register it; setting DriverName to something else requires the caller to import that driver instead.
const DevEnvExample = `` /* 188-byte string literal not displayed */
Single Database (Development)
const ProdClusterExample = `` /* 812-byte string literal not displayed */
Primary/Replica Cluster (Production)
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ClusterConfig ¶
type ClusterConfig struct {
// Connection URLs
WriterURL string // Primary writer connection
ReaderURLs []string // Read replica connections
// Writer detection
WriterDetectionStrategy WriterDetectionStrategy
WriterDetectionQuery string // Custom query to detect writer
WriterDNSName string // DNS name that always points to writer
// Connection pooling
MaxOpenConns int // Maximum open connections per node
MaxIdleConns int // Maximum idle connections per node
ConnMaxLifetime time.Duration // Connection lifetime
ConnMaxIdleTime time.Duration // Connection idle timeout
// Health and retry settings
HealthCheckInterval time.Duration // How often to check node health
RetryAttempts int // Max retry attempts for connections
RetryBackoffBase time.Duration // Base backoff duration
RetryBackoffMax time.Duration // Maximum backoff duration
// Circuit breaker
CircuitBreakerThreshold int // Failures before opening circuit
CircuitBreakerTimeout time.Duration // Circuit breaker timeout
// Read balancing
ReadBalanceStrategy string // "round_robin", "random", "priority", "least_connections"
// Service identification
ServiceName string
// DriverName is the database/sql driver used to open each node.
// Defaults to DefaultDriverName.
DriverName string
}
ClusterConfig holds configuration for the database cluster manager
func LoadConfigFromEnv ¶
func LoadConfigFromEnv(serviceName string) (*ClusterConfig, error)
LoadConfigFromEnv loads database cluster configuration from environment variables
func (*ClusterConfig) String ¶
func (c *ClusterConfig) String() string
String returns a string representation of the configuration
func (*ClusterConfig) Validate ¶
func (c *ClusterConfig) Validate() error
Validate ensures the configuration is valid
type ClusterManager ¶
type ClusterManager struct {
// contains filtered or unexported fields
}
ClusterManager manages connections to multiple PostgreSQL nodes
func NewClusterManager ¶
func NewClusterManager(config ClusterConfig) (*ClusterManager, error)
NewClusterManager creates a new database cluster manager
func (*ClusterManager) Close ¶
func (cm *ClusterManager) Close() error
Close gracefully shuts down all connections. Every node is closed even if an earlier one failed; the failures are joined into the returned error rather than discarded, which is what this method used to do.
func (*ClusterManager) DB ¶
DB returns the writer when ctx carries a write hint from WithWriter, and a read replica otherwise.
func (*ClusterManager) ForceWriterDetection ¶
func (cm *ClusterManager) ForceWriterDetection()
ForceWriterDetection triggers immediate writer detection
func (*ClusterManager) GetNodeStats ¶
func (cm *ClusterManager) GetNodeStats() map[string]NodeStats
GetNodeStats returns statistics for all nodes
func (*ClusterManager) HealthCheck ¶
func (cm *ClusterManager) HealthCheck() error
HealthCheck performs a comprehensive health check of the cluster
func (*ClusterManager) Reader ¶
func (cm *ClusterManager) Reader() (*sql.DB, error)
Reader returns a connection pool for reads, chosen by the configured balancing strategy. The writer participates in read balancing alongside the replicas -- a primary serves reads too -- so a single-node deployment and a deployment whose replicas are all down both keep serving.
func (*ClusterManager) SetWriterNode ¶
func (cm *ClusterManager) SetWriterNode(nodeName string) error
SetWriterNode manually sets a node as the writer (for emergencies)
func (*ClusterManager) WithReader ¶
func (cm *ClusterManager) WithReader(ctx context.Context) context.Context
WithReader returns a context that routes DB to a read replica.
func (*ClusterManager) WithWriter ¶
func (cm *ClusterManager) WithWriter(ctx context.Context) context.Context
WithWriter returns a context that routes DB to the writer.
type DatabaseNode ¶
type DatabaseNode struct {
URL string
Name string
Role NodeRole
Health NodeHealth
Priority int // Lower number = higher priority for reads
// contains filtered or unexported fields
}
DatabaseNode represents a single PostgreSQL instance
type NodeHealth ¶
type NodeHealth int
NodeHealth represents the health state of a database node
const ( HealthHealthy NodeHealth = iota HealthDegraded HealthFailed )
func (NodeHealth) String ¶
func (h NodeHealth) String() string
type NodeStats ¶
type NodeStats struct {
URL string
Role NodeRole
Health NodeHealth
Priority int
ReadCount int64
WriteCount int64
ErrorCount int64
ResponseTime time.Duration
LastError error
LastCheck time.Time
PoolStats sql.DBStats
}
NodeStats holds statistics for a single database node
type TombManager ¶
type TombManager struct {
// contains filtered or unexported fields
}
TombManager provides graceful background task management for database cluster components
func NewTombManager ¶
func NewTombManager(serviceName string) *TombManager
NewTombManager creates a new background task manager for database operations
func (*TombManager) Context ¶
func (tm *TombManager) Context() context.Context
Context returns the cancellation context for manual task management
func (*TombManager) IsShuttingDown ¶
func (tm *TombManager) IsShuttingDown() bool
IsShuttingDown returns true if the tomb manager is shutting down
func (*TombManager) Shutdown ¶
func (tm *TombManager) Shutdown()
Shutdown gracefully stops all background tasks
func (*TombManager) StartBackgroundTask ¶
func (tm *TombManager) StartBackgroundTask(taskFn func(ctx context.Context), taskName string)
StartBackgroundTask starts a background task with proper lifecycle management
func (*TombManager) WaitGroup ¶
func (tm *TombManager) WaitGroup() *sync.WaitGroup
WaitGroup returns the wait group for manual task management
type WriterDetectionStrategy ¶
type WriterDetectionStrategy int
WriterDetectionStrategy defines how to detect the writer node
const ( StrategyDNS WriterDetectionStrategy = iota // DNS-based (writer.db.example.com) StrategyQuery // SQL query-based detection StrategyConfig // Configuration-based (explicit writer) StrategyProbe // Health probe-based detection )