proc primaryPool(cluster: PgPoolCluster): PgPool {....raises: [], tags: [], forbids: [].}
Types
PgPoolCluster = ref object
-
Connection pool cluster with explicit read/write routing.
- readConnection() / withReadConnection route to the replica pool.
- writeConnection() / withWriteConnection route to the primary pool.
For transactions, use cluster.withTransaction.
ReadFallbackCallback = proc (reason: ReadFallbackReason; err: ref CatchableError) {. ...gcsafe, raises: [].}
-
Advisory hook fired when acquireRead (and therefore readConnection / withReadConnection) falls back from the replica pool to the primary pool. Fires only when fallback == fallbackPrimary, once per read that falls back, before the primary acquire is attempted. err is the replica failure that triggered the fallback. Advisory only — routing is unchanged. Use it to detect a replica that is down or saturated before all read load silently lands on the primary. Must not raise.
Fires per fallback, not per state change. A permanently closed or saturated replica fires this on every read for as long as the condition lasts (rfrReplicaClosed / rfrReplicaTimeout), which can be very high frequency under load. This suits counters/metrics, where each fallback should be counted; for logging or alerting, dedupe or rate-limit on the observer side.
ReadFallbackReason = enum rfrReplicaUnavailable, ## The replica `acquire()` failed before `fallbackTimeout` elapsed ## (e.g. saturation, acquire-queue full, connect failure). rfrReplicaClosed, ## The replica pool was closed (`isClosed`). A permanently closed ## replica routes *every* read to the primary — observe this to detect ## a cluster that has silently degraded to primary-only. rfrReplicaTimeout ## The replica `acquire()` exceeded `fallbackTimeout` and was abandoned ## in favour of the primary.
- Why acquireRead fell back from the replica pool to the primary pool.
ReplicaFallback = enum fallbackNone, ## Error when replica is unavailable fallbackPrimary ## Fall back to primary when replica is unavailable
Procs
proc close(cluster: PgPoolCluster; timeout = ZeroDuration): Future[void] {. ...stackTrace: false, raises: [Exception, CatchableError], tags: [RootEffect, TimeEffect], forbids: [].}
- Close both primary and replica pools.
proc fallbackTimeout(cluster: PgPoolCluster): Duration {....raises: [], tags: [], forbids: [].}
- The configured fallback timeout for read operations. When fallbackPrimary is set, this bounds both the replica acquire and the fallback primary acquire, so a saturated replica cannot stall a read for its full acquireTimeout before the fallback engages. ZeroDuration leaves each pool's own acquireTimeout in force (the replica acquire then blocks up to the replica pool's acquireTimeout before falling back).
proc isClosed(cluster: PgPoolCluster): bool {....raises: [], tags: [], forbids: [].}
- Whether the cluster has been closed.
proc newPoolCluster(primaryConfig: PoolConfig; replicaConfig: PoolConfig; fallback = fallbackNone; fallbackTimeout = ZeroDuration; onReadFallback: ReadFallbackCallback = nil): Future[ PgPoolCluster] {....stackTrace: false, raises: [Exception, ValueError, CatchableError], tags: [RootEffect, TimeEffect, WriteIOEffect], forbids: [].}
-
Create a new pool cluster with separate primary and replica pools. If connConfig.targetSessionAttrs is tsaAny (the default), it is automatically set to tsaReadWrite for primary and tsaPreferStandby for replica.
With fallback == fallbackPrimary, fallbackTimeout (when > ZeroDuration) bounds both the replica and the fallback primary acquire so a saturated replica fails over promptly instead of blocking for its full acquireTimeout. onReadFallback is an optional advisory hook invoked on each replica->primary read fallback (see ReadFallbackCallback).
proc onReadFallback(cluster: PgPoolCluster): ReadFallbackCallback {....raises: [], tags: [], forbids: [].}
- The configured replica->primary read-fallback observability hook (see ReadFallbackCallback).
- The primary (read-write) pool.
proc readConnection(cluster: PgPoolCluster): Future[PooledConnHandle] {. ...stackTrace: false, raises: [Exception, ValueError, PgPoolError, CatchableError, PgError, CancelledError], tags: [RootEffect, TimeEffect, WriteIOEffect], forbids: [].}
-
Acquire a read connection from the replica pool (with optional primary fallback per ReplicaFallback) wrapped in a PooledConnHandle.
The caller must release the handle — typically via defer: h.release(). Forgetting to release leaks the connection until the pool is closed. h.pool reflects which pool actually served the acquire (replica or primary on fallback), so use it for any pool-level operations on the borrowed connection.
No session reset on release. Prefer withReadConnection when the body is a single block and automatic resetSession is desired; use readConnection when the handle must outlive a single lexical scope (e.g. stored in a struct, passed across await boundaries through multiple helpers, or selected dynamically).
proc replicaFallback(cluster: PgPoolCluster): ReplicaFallback {....raises: [], tags: [], forbids: [].}
- The configured replica fallback behavior.
proc replicaPool(cluster: PgPoolCluster): PgPool {....raises: [], tags: [], forbids: [].}
- The replica (read-only) pool.
proc writeConnection(cluster: PgPoolCluster): Future[PooledConnHandle] {. ...stackTrace: false, raises: [Exception, ValueError, PgPoolError, CatchableError, PgError, CancelledError], tags: [RootEffect, TimeEffect, WriteIOEffect], forbids: [].}
-
Acquire a write connection from the primary pool, wrapped in a PooledConnHandle.
The caller must release the handle — typically via defer: h.release(). Forgetting to release leaks the connection until the pool is closed.
No session reset on release. Prefer withWriteConnection when the body is a single block and automatic resetSession is desired; use writeConnection when the handle must outlive a single lexical scope. For transactional work, use cluster.withTransaction instead — handles are not transaction-aware.
Macros
macro withTransaction(cluster: PgPoolCluster; args: varargs[untyped]): untyped
-
Execute body inside a BEGIN/COMMIT transaction on the primary pool. On exception, ROLLBACK is issued automatically. Using return inside the body is a compile-time error.
Usage: cluster.withTransaction(conn): conn.exec(...) cluster.withTransaction(conn, seconds(5)): conn.exec(...) cluster.withTransaction(conn, TransactionOptions(isolation: ilSerializable)): conn.exec(...) cluster.withTransaction(conn, opts, seconds(5)): conn.exec(...)
Warning: Inside the body, run statements on the bound conn directly (conn.exec(...) / conn.query(...)). Calling cluster.writeConnection() / cluster.readConnection() inside the body acquires a separate connection from the pool, so any statements issued through that handle run outside this transaction.
macro withTransactionRetry(cluster: PgPoolCluster; retryOpts: RetryOptions; args: varargs[untyped]): untyped
-
Execute body inside a BEGIN/COMMIT transaction on the primary pool, re-running the whole transaction when it fails with a retryable error (by default the serialization_failure / deadlock_detected SQLSTATEs — see RetryOptions). The primary connection is acquired once and reused across attempts. On a non-retryable error, or once maxAttempts is exhausted, the last exception propagates. Using return inside the body is a compile-time error.
Usage: cluster.withTransactionRetry(RetryOptions(maxAttempts: 3), conn): await conn.exec(...) cluster.withTransactionRetry(RetryOptions(...), conn, seconds(5)): await conn.exec(...) cluster.withTransactionRetry(RetryOptions(...), conn, opts, seconds(5)): await conn.exec(...)
Idempotency: body runs once per attempt; non-database side effects are repeated on every retry. See withTransaction for the in-body conn warning.
Templates
template withPipeline(cluster: PgPoolCluster; pipeline, body: untyped)
- Create a pipeline on the primary pool.
template withReadConnection(cluster: PgPoolCluster; conn, body: untyped)
- Acquire a read connection (from replica, with optional primary fallback), execute body, then release.
template withWriteConnection(cluster: PgPoolCluster; conn, body: untyped)
- Acquire a write connection from the primary pool, execute body, then release.