fix(db): isolate billing and auth connection pools, release the redeploy-check transaction early, cache integration tool schemas

Merged
WA
6d ago
+622-216

Summary

  • Billing writes and auth lookups get their own connection pools (dbFor('billing'), 4 connections; dbFor('auth'), 3). When slow work saturates a process's 10-connection pool, postgres.js pipelines new queries onto busy connections, so a billing transaction's BEGIN could wait behind a large result and be killed by its 4s transaction_timeout. Settlement transactions (recordCumulativeUsage, recordUsage fallback, threshold billing, the execution-logger usage reconcile, job spend) and the auth adapter, getAuthDatabase() fallback and API-key lookup now run on their own clients. App-wide billing reads stay on db so they don't crowd a small pool
  • isPrimaryPoolClient() in @sim/db replaces the executor === db checks that gate the auth policy caches and the reporting usage cache, so those caches still apply on a sub-pool client and never on a transaction or the replica
  • DATABASE_URL_BILLING / DATABASE_URL_AUTH are optional; unset, the pools fall back to the process URL, which already gives the client-side isolation
  • checkNeedsRedeployment keeps every read in its REPEATABLE READ snapshot but runs the state diff after commit, so the connection is no longer held idle in transaction during the comparison
  • Integration tool schemas are built once per process per surface/mode, frozen and shared, instead of per viewer with a 5s TTL (every call rebuilt ~5.3k schemas, stringified them to size the cache and deep-cloned them). Viewer gating and the plan-dependent email tagline still apply per request; output is byte-identical. BM25 term counts are memoized per shared schema

Type of Change

  • Bug fix

Testing

  • New lib/db/pool-isolation.integration.ts: fills every connection of the real db pool, then requires a cumulative usage write, an auth adapter session read and an API-key lookup to finish within 1.5s. Fails on the pre-fix code (all three stall), passes with the fix
  • Integration: pool-isolation, usage-log, reporting-usage-cache, get-organization-plan-seats (57 tests) against disposable Postgres
  • Unit: new deployment-status.test.ts (diff no longer runs while the transaction is open; red pre-fix), db.test.ts, auth cache-identity case in security-policy.test.ts (red with executor === db), payload tests (one build per process, cross-viewer isolation, tagline per viewer; red pre-fix), plus 54 neighbouring files (635 tests)
  • check:tool-registry-boundary, check:schema-mock, check:test-patterns, check:utils, check:comment-hygiene, check:unused-exports, check:file-names; generators in sync. Type-check and full audits run in CI

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing (new tests pass the test-audit authoring gate)
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)