Skip to content

feat(console-api): add an optional pgbouncer in front of the database - #601

Open
baktun14 wants to merge 1 commit into
mainfrom
feat/console-api-pgbouncer-transaction-pooler
Open

baktun14 wants to merge 1 commit into
mainfrom
feat/console-api-pgbouncer-transaction-pooler

Conversation

@baktun14

@baktun14 baktun14 commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Why

Console API database connections grow with pod count, because every API, bg-jobs, stats and cron pod opens its own pools against Cloud SQL. Cloud SQL Managed Connection Pooling needs Enterprise Plus and our instance is on Enterprise, so the pooler runs in the cluster.

Ref CON-1354

What

  • An optional pgbouncer block in the console-api chart, off by default. When enabled, each release gets console-api-<chain>-pgbouncer: a Deployment (2 replicas, preferred anti-affinity), a Service on 5432, a PodDisruptionBudget and a ConfigMap holding pgbouncer.ini.
  • PgBouncer 1.26.1 (edoburu/pgbouncer:v1.26.1-p0) runs in transaction mode in front of cloudsql-proxy-console-api. A wildcard database entry serves both the user DB and the chain DB. max_prepared_statements = 200 keeps postgres.js prepared statements working.
  • The userlist comes from a new PGBOUNCER_USERLIST key in the release's Doppler secret (one "user" "password" line per database user), mounted as a file. The container starts pgbouncer directly instead of the image entrypoint, because the entrypoint truncates passwords at a : and doesn't decode URL-encoded characters.
  • Server connections are capped at defaultPoolSize (20) per database and user on each replica, so a release with both databases opens at most 80.
  • Chart version 0.12.0.

Rollout, staging first:

  1. In Doppler, add PGBOUNCER_USERLIST and set POSTGRES_MIGRATION_DB_URI to the current direct URI.
  2. Set pgbouncer.enabled: true in the console repo's .helm/console-api-staging-<chain>-values.yaml and deploy.
  3. Point POSTGRES_DB_URI and CHAIN_INDEXER_POSTGRES_DB_URI at console-api-<chain>-pgbouncer:5432. This step needs fix(config): let the api run behind a transaction-mode connection pooler console#4646 deployed first, so migrations keep a direct connection.

Testing:

  • ct lint passes. With pgbouncer.enabled unset, the chart renders exactly as before.
  • I rendered pgbouncer.ini and ran it with the pinned image and the same command against a local Postgres that requires SCRAM. Both databases were reachable through the wildcard entry, a wrong password was rejected, postgres.js with prepared statements on completed 450/450 queries and transactions, and node-postgres (pg-boss's driver) connected.

Every API, bg-jobs, stats and cron pod opens its own pools against Cloud SQL,
so connections grow with pod count. Managed connection pooling needs Cloud SQL
Enterprise Plus, so the pooler runs in the cluster instead: PgBouncer 1.26 in
transaction mode in front of cloudsql-proxy-console-api, off by default, with
its userlist read from a PGBOUNCER_USERLIST key in the release's Doppler secret.

Refs CON-1354
@baktun14
baktun14 requested a review from a team as a code owner November 1, 2026 05:27

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant