Skip to content

Commit 2fa2011

Browse files
committed
fix: set the statement_timeout at query level
1 parent e41138a commit 2fa2011

File tree

2 files changed

+10
-11
lines changed

2 files changed

+10
-11
lines changed

src/lib/db.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import pg from 'pg'
22
import * as Sentry from '@sentry/node'
33
import { parse as parseArray } from 'postgres-array'
44
import { PostgresMetaResult, PoolConfig } from './types.js'
5+
import { PG_STATEMENT_TIMEOUT_SECS } from '../server/constants.js'
56

67
pg.types.setTypeParser(pg.types.builtins.INT8, (x) => {
78
const asNumber = Number(x)
@@ -80,11 +81,6 @@ export const init: (config: PoolConfig) => {
8081
u.searchParams.delete('sslrootcert')
8182
config.connectionString = u.toString()
8283

83-
// For pooler connections like pgbouncer, statement_timeout isn't supported
84-
if (u.port !== '5432') {
85-
config.statement_timeout = undefined
86-
}
87-
8884
// sslmode: null, 'disable', 'prefer', 'require', 'verify-ca', 'verify-full', 'no-verify'
8985
// config.ssl: true, false, {}
9086
if (sslmode === null) {
@@ -117,18 +113,23 @@ export const init: (config: PoolConfig) => {
117113
attributes: { sql: trackQueryInSentry ? sql : 'custom' },
118114
},
119115
async () => {
116+
// node-postgres need a statement_timeout to kill the connection when timeout is reached
117+
// otherwise the query will keep running on the database even if query timeout was reached
118+
// This need to be added at query and not connection level because poolers (pgbouncer) doesn't
119+
// allow to set this parameter at connection time
120+
const sqlWithStatementTimeout = `SET statement_timeout='${PG_STATEMENT_TIMEOUT_SECS}s';\n${sql}`
120121
try {
121122
if (!pool) {
122123
const pool = new pg.Pool(config)
123-
let res = await poolerQueryHandleError(pool, sql)
124+
let res = await poolerQueryHandleError(pool, sqlWithStatementTimeout)
124125
if (Array.isArray(res)) {
125126
res = res.reverse().find((x) => x.rows.length !== 0) ?? { rows: [] }
126127
}
127128
await pool.end()
128129
return { data: res.rows, error: null }
129130
}
130131

131-
let res = await poolerQueryHandleError(pool, sql)
132+
let res = await poolerQueryHandleError(pool, sqlWithStatementTimeout)
132133
if (Array.isArray(res)) {
133134
res = res.reverse().find((x) => x.rows.length !== 0) ?? { rows: [] }
134135
}
@@ -158,7 +159,7 @@ export const init: (config: PoolConfig) => {
158159
let lineNumber = 0
159160
let lineOffset = 0
160161

161-
const lines = sql.split('\n')
162+
const lines = sqlWithStatementTimeout.split('\n')
162163
let currentOffset = 0
163164
for (let i = 0; i < lines.length; i++) {
164165
if (currentOffset + lines[i].length > position) {

src/server/constants.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const PG_META_DB_SSL_MODE = process.env.PG_META_DB_SSL_MODE || 'disable'
1717

1818
const PG_CONN_TIMEOUT_SECS = Number(process.env.PG_CONN_TIMEOUT_SECS || 15)
1919
const PG_QUERY_TIMEOUT_SECS = Number(process.env.PG_QUERY_TIMEOUT_SECS || 55)
20+
export const PG_STATEMENT_TIMEOUT_SECS = PG_QUERY_TIMEOUT_SECS + 1
2021

2122
export let PG_CONNECTION = process.env.PG_META_DB_URL
2223
if (!PG_CONNECTION) {
@@ -59,9 +60,6 @@ export const PG_META_MAX_RESULT_SIZE = process.env.PG_META_MAX_RESULT_SIZE_MB
5960
export const DEFAULT_POOL_CONFIG: PoolConfig = {
6061
max: 1,
6162
connectionTimeoutMillis: PG_CONN_TIMEOUT_SECS * 1000,
62-
// node-postgrest need a statement_timeout to kill the connection when timeout is reached
63-
// otherwise the query will keep running on the database even if query timeout was reached
64-
statement_timeout: (PG_QUERY_TIMEOUT_SECS + 1) * 1000,
6563
query_timeout: PG_QUERY_TIMEOUT_SECS * 1000,
6664
ssl: PG_META_DB_SSL_ROOT_CERT ? { ca: PG_META_DB_SSL_ROOT_CERT } : undefined,
6765
application_name: `postgres-meta ${pkg.version}`,

0 commit comments

Comments
 (0)