Documentation
¶
Overview ¶
Package postgres implements leaderelection.Store on top of PostgreSQL using pgx.
It is designed to behave identically on a direct connection and through PgBouncer in transaction pooling mode, which is the usual way a fleet spread across clusters reaches a shared database. Nothing here uses session-scoped state: no session advisory locks, no LISTEN/NOTIFY, no temporary tables, no SET, and no server-side prepared statements. Every operation is a single autocommit statement.
The election's guarantees depend on all timestamps coming from the database server, so every statement returns the server's current time alongside the lease. See the leaderelection package documentation for why.
Index ¶
- Constants
- func Fatal(err error) bool
- func Retryable(err error) bool
- func Schema(schema, table string) (string, error)
- type Option
- type Store
- func (s *Store) Acquire(ctx context.Context, name, identity string, ttl time.Duration, payload []byte) (leaderelection.Lease, error)
- func (s *Store) Close()
- func (s *Store) EnsureSchema(ctx context.Context) error
- func (s *Store) Inspect(ctx context.Context, name string) (leaderelection.Lease, error)
- func (s *Store) Release(ctx context.Context, name, identity string, fence int64) error
- func (s *Store) Renew(ctx context.Context, name, identity string, fence int64, ttl time.Duration, ...) (leaderelection.Lease, error)
- func (s *Store) Table() string
Constants ¶
const DefaultTable = "leader_election"
DefaultTable is the table name used when none is configured.
Variables ¶
This section is empty.
Functions ¶
func Fatal ¶
Fatal reports whether err describes a deployment problem that will not resolve without intervention: a missing table, missing privileges, a schema that does not match.
It is the signal worth alerting on. A fatal error means this participant will never win an election until somebody fixes something.
func Retryable ¶
Retryable reports whether err is a transient condition that is expected to clear on its own: a dropped connection, a pooler cycling, a deadlock, a serialization conflict, an administrator bouncing the server, a call that ran out of time.
A retryable error means the operation may be attempted again. It never means the caller may assume it is still the leader.
Errors are classified as this package returns them, which is wrapped. Every check here goes through errors.Is or errors.As for that reason.
func Schema ¶
Schema returns the DDL for a leader-election table, for callers who manage their schema with a migration tool rather than with Store.EnsureSchema.
schema may be empty to use the connection's search path. Both identifiers are validated, and Schema returns an error rather than emitting anything it could not validate.
Types ¶
type Option ¶
type Option func(*options)
Option configures a Store.
func WithTable ¶
WithTable selects the table holding the leases. schema may be empty to use the connection's search path.
Both identifiers must be simple unquoted names; anything else is rejected rather than quoted, because the table name is the only part of these statements that cannot be a bind parameter.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is a PostgreSQL-backed leaderelection.Store.
func Connect ¶
Connect builds a pool from dsn and returns a Store that owns it.
The pool is configured to work through PgBouncer in transaction pooling mode as well as directly:
- The query exec mode is pgx.QueryExecModeExec, which sends each statement without naming a prepared statement on the server. Named prepared statements are per-session, so under transaction pooling they end up on whichever server connection the pooler hands out next and produce "prepared statement does not exist" at random. The cost is negligible for the handful of statements this package runs.
- The statement and description caches are disabled for the same reason.
- Connection lifetimes and health checks are bounded, so the pool sheds connections that a pooler restart left in an unusable state instead of discovering them one failed election at a time.
Settings expressed in dsn are honoured, with one exception. pgx does not distinguish "the DSN asked for cache_statement" from "the DSN said nothing", so a DSN that asks for it explicitly is still moved to exec mode. Any other exec mode is left alone, and a caller who wants statement caching against a direct connection can build the pool themselves and pass it to New.
func New ¶
New returns a Store that uses db.
The caller keeps ownership of the pool: Store.Close does not close it. Use this when the application already has a pool, and Connect when it does not.
A pool built by the caller must tolerate a connection pooler if one is in the path. In particular its query exec mode must not rely on named prepared statements; see Connect for the settings this package would have chosen.
func (*Store) Acquire ¶
func (s *Store) Acquire(ctx context.Context, name, identity string, ttl time.Duration, payload []byte) (leaderelection.Lease, error)
Acquire implements leaderelection.Store.
func (*Store) Close ¶
func (s *Store) Close()
Close releases resources the Store owns. A pool passed to New belongs to the caller and is left open; one created by Connect is closed.
func (*Store) EnsureSchema ¶
EnsureSchema creates the leases table if it does not exist. It is idempotent and safe to call from every replica on every start.
It needs CREATE on the schema. Deployments that withhold DDL rights from the application should run Schema through their migration tool instead.
func (*Store) Inspect ¶
Inspect implements leaderelection.Store.
func (*Store) Release ¶
Release implements leaderelection.Store.