Skip to main content

Connection Pool Configuration

Each service has a configured connection pool size based on its workload. Set via DB_MAX_CONNS and DB_MIN_CONNS environment variables per service.

Connection Budget Formula

Example with 2 instances per service:
Example with 3 instances per stateless service:
Note: Health evaluator uses leader election — only 1 active instance needs connections. Scale triggers for PgBouncer at N=10 connection pools.

Tuning

If db_pool_active_connections exceeds 80% of MaxConns or db_pool_acquire_duration_seconds p99 exceeds 1s:
  1. Check if queries are slow (see Statement Timeout Runbook below)
  2. Increase DB_MAX_CONNS for the affected service
  3. Recalculate connection budget to ensure it stays under max_connections
  4. If total budget exceeds PostgreSQL limits, deploy PgBouncer

Statement Timeouts

Per-service statement timeouts prevent runaway queries from holding connections. Set via DB_STATEMENT_TIMEOUT environment variable. When a query exceeds the timeout, PostgreSQL cancels it and returns error code 57014. The application logs the timeout and the request fails with an appropriate error. Adjusting timeouts: If legitimate queries are timing out, investigate the root cause before increasing the timeout. See the Statement Timeout Runbook below.

PostgreSQL Configuration Requirements

pg_stat_statements (Required)

Enable in PostgreSQL configuration:
Requires PostgreSQL restart. Coordinate with managed PostgreSQL deployment.

Slow Query Logging

Logs all queries exceeding 500ms with full query text. This threshold is lower than statement timeouts (2-10s) to catch degradation before it becomes a timeout.

Query Performance SLOs (p95)

Application-Side Metrics

The following Prometheus metrics are automatically emitted by all services via the shared database connection setup:

Alert Thresholds

Statement Timeout Runbook

When statement timeouts trigger frequently:
  1. Identify the query: Check hoodcloud_db_statement_timeout_total metric labels for the service. Cross-reference with pg_stat_statements for recently degraded queries.
  2. Check for lock contention:
    Health evaluator batch updates and API server reads can contend.
  3. Check for table bloat:
    The nodes and node_health_state tables are high-write and bloat-prone.
  4. Check for missing indexes: Run EXPLAIN ANALYZE on the timed-out query. Verify indexes exist on all JOIN and WHERE columns.
  5. Check for data growth: If node count has grown significantly, ListSnapshots may need pagination or the health evaluator’s statement timeout may need adjustment.
  6. Temporary mitigation: If a single runaway query is causing cascading timeouts, identify and pg_cancel_backend() it. Do NOT increase statement timeouts without understanding root cause.
  7. Escalation: If timeouts persist after steps 1-6, this may indicate the scale trigger for PgBouncer or a health read replica.