fix(config): keep no PostgreSQL connection warm by default, idle timeout back to 10 s

Merged
EV
9d ago
+58-20

Why

Stage API (apistage.gauzy.co) stalled after the develop → stage promotion 61d0d6750a rolled out at 15:42Z.

  • #10976 (38988ff788) changed the defaults to DB_POOL_MIN 2 and DB_IDLE_TIMEOUT 30 s. That was measured on a direct PostgreSQL connection.
  • Hosted stage and production reach PostgreSQL through a session-mode PgBouncer. There, every open client connection, idle or not, holds one server connection.
  • On stage that pooler has 4 server connections per instance (12 in total), shared by the API, the worker and the Teams API. gauzy_stage sat at 12/12. New client connections waited in PgBouncer for up to 98 s (cnpg_pgbouncer_pools_maxwait).
  • In the API logs this looked like slow queries: SELECT version() 67 s at boot, timesheet/statistics/counts 94 s.

Change

  • DEFAULT_DB_IDLE_TIMEOUT_MS 30000 → 10000, and a new DEFAULT_DB_POOL_MIN = 0 (was a literal 2).
  • Both env knobs stay. A direct connection or a transaction-mode PgBouncer can opt in to DB_POOL_MIN=2 and DB_IDLE_TIMEOUT=30000. The doc comment on DEFAULT_DB_IDLE_TIMEOUT_MS and .env.sample say when that is safe.
  • Unchanged: keep-alive, application_name, the opt-in server-side timeouts, and the MikroORM / Knex pools (min 0 already).
  • Specs updated: the defaults test now expects min 0 and 10 s, the opt-in test covers min 2 and 30 s, an invalid DB_POOL_MIN falls back to 0, and the startup log line reads DB Idle Timeout: 10000.
  • Prettier also re-wrapped one existing line (DB_KEEP_ALIVE check) in database.ts. Formatting only.

Agreed with the author of #10976 (the perf session), who asked for the session-pooler note.

Verification

  • packages/config/src/lib/database-config-validation.spec.ts: 60/60 pass; tsc -p packages/config/tsconfig.lib.json clean.
  • The same two values are already live on stage as env overrides via ever-co/k8s-gitops#219, so the stage API recovers before this PR reaches stage.

Rollout

develop → stage only. Owner rule: no stage → master for now. Prod's pooler is also session mode, so this has to land before #10976 ever reaches master.

🤖 Generated with Claude Code


Summary by cubic

Reverts the default PostgreSQL pool settings so no connection is kept warm and idle ones close after 10 s, preventing the API from stalling when PostgreSQL is reached through a session-mode PgBouncer.

  • #10976 raised the defaults to DB_POOL_MIN=2 and 30 s idle timeout, measured against a direct connection; behind a session-mode PgBouncer every open client connection holds a server connection, which saturated the stage pooler (12/12) and made new connections wait up to 98 s.
  • The defaults are back to min 0 and 10 s; direct connections and transaction-mode PgBouncers can opt in via DB_POOL_MIN=2 / DB_IDLE_TIMEOUT=30000.
  • DB_POOL_MIN applies to the active ORM's pool only; the Knex pool always keeps none.
  • Unchanged: keep-alive, application_name, and the opt-in server-side timeouts.

Migration

  • Re-deploy stage only; DB_POOL_MIN=2 and DB_IDLE_TIMEOUT=30000 must not reach the session-mode pooler, so this has to land before #10976 reaches master.