4 months ago
36a43e7PlanetScale's pooler drops the session a LISTEN needs, so the app uses two URLs: DATABASE_URL (pooled) for transactional/query work + pg-boss, and DATABASE_URL_DIRECT (direct/session) for LISTEN/NOTIFY only. New createDirectPool() falls back to DATABASE_URL when direct is unset, so local dev is unchanged. The api SSE stream holds its LISTEN on the direct pool; the worker's pool (pg_notify only) is the direct pool, queries + pg-boss stay pooled. New 'bun run verify:planetscale' gates cutover, exiting non-zero on failure: - A. transaction affinity on the pooled URL, PROVEN BY ROLLBACK: runs the real ingest (INSERT event + pg-boss enqueue in one tx), confirms atomic commit, then rolls back a second attempt and asserts neither row nor job survived. - B. LISTEN/NOTIFY on the direct URL, payload asserted within 7s. If B fails the script STOPS — no polling fallback (that is a spec decision, not ours). Verified: exits 0 against compose Postgres, exits 1 when DATABASE_URL_DIRECT is unset; 52 api/db/worker tests pass; typecheck + biome + boundaries clean.
Parent6316fbe