From e9d424eb806d43dccc37a45a4d75e09bb901c2f6 Mon Sep 17 00:00:00 2001 From: Owen Date: Tue, 7 Jul 2026 10:41:12 -0400 Subject: [PATCH] Move jit mode to a config param Ref #3262 --- server/db/pg/poolConfig.ts | 35 ++++++++++++++++++++++++----------- server/lib/readConfigFile.ts | 3 ++- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/server/db/pg/poolConfig.ts b/server/db/pg/poolConfig.ts index af6c10520..2f3f93a62 100644 --- a/server/db/pg/poolConfig.ts +++ b/server/db/pg/poolConfig.ts @@ -1,3 +1,4 @@ +import config from "@server/lib/config"; import { Pool, PoolConfig } from "pg"; export function createPoolConfig( @@ -18,17 +19,7 @@ export function createPoolConfig( keepAliveInitialDelayMillis: 10000, // send first keepalive after 10s of idle // Allow connections to be released and recreated more aggressively // to avoid stale connections building up - allowExitOnIdle: false, - // Disable JIT compilation for this connection. Our hot-path queries - // (e.g. resource-by-domain lookups) join many tables but only ever - // return a handful of rows. When planner row estimates drift (e.g. - // due to autovacuum lag under write-heavy load), Postgres decides - // these plans are expensive enough to JIT-compile, which can add - // multiple seconds of pure compilation overhead per query and - // saturate the connection pool. JIT never pays off for these - // short-lived OLTP queries, so it's disabled outright rather than - // relying on statistics staying fresh. - options: "-c jit=off" + allowExitOnIdle: false }; } @@ -49,6 +40,28 @@ export function attachPoolErrorHandlers(pool: Pool, label: string): void { `Failed to set statement_timeout on ${label} client: ${err.message}` ); }); + + // Disable JIT compilation for this connection. Our hot-path queries + // (e.g. resource-by-domain lookups) join many tables but only ever + // return a handful of rows. When planner row estimates drift (e.g. + // due to autovacuum lag under write-heavy load), Postgres decides + // these plans are expensive enough to JIT-compile, which can add + // multiple seconds of pure compilation overhead per query and + // saturate the connection pool. JIT never pays off for these + // short-lived OLTP queries, so it's disabled outright rather than + // relying on statistics staying fresh. + // + // Set via a runtime SET command rather than the `options: "-c + // jit=off"` startup parameter: connections in SaaS mode go through + // a pooler (e.g. PgBouncer) that rejects arbitrary startup packet + // options with a protocol_violation (08P01) error. + if (config.getRawConfig().postgres?.pool.jit_mode == false) { + client.query("SET jit = off").catch((err: Error) => { + console.warn( + `Failed to set jit=off on ${label} client: ${err.message}` + ); + }); + } }); } diff --git a/server/lib/readConfigFile.ts b/server/lib/readConfigFile.ts index c3e796fc1..6b6ac95aa 100644 --- a/server/lib/readConfigFile.ts +++ b/server/lib/readConfigFile.ts @@ -184,7 +184,8 @@ export const configSchema = z .number() .positive() .optional() - .default(5000) + .default(5000), + jit_mode: z.boolean().default(true) }) .optional() .prefault({})