Skip to content

Commit ac5f883

Browse files
committed
Update build files
1 parent 959c720 commit ac5f883

File tree

8 files changed

+122
-3
lines changed

8 files changed

+122
-3
lines changed

cf/src/connection.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,11 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
254254
}
255255

256256
function nextWrite(fn) {
257+
if (!socket) {
258+
// Connection was closed, cannot write
259+
chunk = nextWriteTimer = null
260+
return false
261+
}
257262
const x = socket.write(chunk, fn)
258263
nextWriteTimer !== null && clearImmediate(nextWriteTimer)
259264
chunk = nextWriteTimer = null
@@ -436,6 +441,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
436441
}
437442

438443
async function closed(hadError) {
444+
terminated = true // Mark connection as terminated to prevent further query attempts
439445
incoming = Buffer.alloc(0)
440446
remaining = 0
441447
incomings = null

cf/src/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,12 +238,13 @@ function Postgres(a, b) {
238238
let savepoints = 0
239239
, connection
240240
, prepare = null
241+
, closed = false
241242

242243
try {
243244
await sql.unsafe('begin ' + options.replace(/[^a-z ]/ig, ''), [], { onexecute }).execute()
244245
return await Promise.race([
245246
scope(connection, fn),
246-
new Promise((_, reject) => connection.onclose = reject)
247+
new Promise((_, reject) => connection.onclose = e => (closed = true, reject(e)))
247248
])
248249
} catch (error) {
249250
throw error
@@ -290,6 +291,8 @@ function Postgres(a, b) {
290291
}
291292

292293
function handler(q) {
294+
if (closed)
295+
return q.reject(Errors.connection('CONNECTION_CLOSED', options))
293296
q.catch(e => uncaughtError || (uncaughtError = e))
294297
c.queue === full
295298
? queries.push(q)

cjs/src/connection.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,11 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
252252
}
253253

254254
function nextWrite(fn) {
255+
if (!socket) {
256+
// Connection was closed, cannot write
257+
chunk = nextWriteTimer = null
258+
return false
259+
}
255260
const x = socket.write(chunk, fn)
256261
nextWriteTimer !== null && clearImmediate(nextWriteTimer)
257262
chunk = nextWriteTimer = null
@@ -434,6 +439,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
434439
}
435440

436441
async function closed(hadError) {
442+
terminated = true // Mark connection as terminated to prevent further query attempts
437443
incoming = Buffer.alloc(0)
438444
remaining = 0
439445
incomings = null

cjs/src/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,12 +237,13 @@ function Postgres(a, b) {
237237
let savepoints = 0
238238
, connection
239239
, prepare = null
240+
, closed = false
240241

241242
try {
242243
await sql.unsafe('begin ' + options.replace(/[^a-z ]/ig, ''), [], { onexecute }).execute()
243244
return await Promise.race([
244245
scope(connection, fn),
245-
new Promise((_, reject) => connection.onclose = reject)
246+
new Promise((_, reject) => connection.onclose = e => (closed = true, reject(e)))
246247
])
247248
} catch (error) {
248249
throw error
@@ -289,6 +290,8 @@ function Postgres(a, b) {
289290
}
290291

291292
function handler(q) {
293+
if (closed)
294+
return q.reject(Errors.connection('CONNECTION_CLOSED', options))
292295
q.catch(e => uncaughtError || (uncaughtError = e))
293296
c.queue === full
294297
? queries.push(q)

cjs/tests/index.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2638,3 +2638,49 @@ t('query during copy error', async() => {
26382638
await sql`drop table test`
26392639
]
26402640
})
2641+
2642+
t('idle_in_transaction_session_timeout causes CONNECTION_CLOSED', { timeout: 5 }, async() => {
2643+
const sql = postgres(options)
2644+
const error = await sql.begin(async(txSql) => {
2645+
await txSql`SET LOCAL idle_in_transaction_session_timeout = '1s'`
2646+
await new Promise(r => setTimeout(r, 2000))
2647+
await txSql`SELECT 1`
2648+
}).catch(e => e)
2649+
await sql.end()
2650+
return [true, error.code === 'CONNECTION_CLOSED' || error.code === 'CONNECTION_DESTROYED']
2651+
})
2652+
2653+
t('txSql fails after idle_in_transaction_session_timeout even if callback continues', { timeout: 5 }, async() => {
2654+
const sql = postgres(options)
2655+
let failed = false
2656+
await sql.begin(async(txSql) => {
2657+
await txSql`SET LOCAL idle_in_transaction_session_timeout = '1s'`
2658+
await new Promise(r => setTimeout(r, 2000))
2659+
try { await txSql`SELECT 1` } catch (e) {
2660+
failed = e.code === 'CONNECTION_CLOSED' || e.code === 'CONNECTION_DESTROYED'
2661+
}
2662+
}).catch(() => { /* ignore */ })
2663+
await new Promise(r => setTimeout(r, 1000))
2664+
await sql.end()
2665+
return [true, failed]
2666+
})
2667+
2668+
t('txSql fails even when pool connection reconnects after idle timeout', { timeout: 10 }, async() => {
2669+
const sql = postgres({ ...options, max: 1 })
2670+
// Queue pool queries to trigger reconnect after connection closes
2671+
for (let i = 0; i < 3; i++)
2672+
setTimeout(() => sql`SELECT ${i}`.catch(() => { /* ignore */ }), 1000 + i * 100)
2673+
2674+
let txSqlSucceeded = false
2675+
await sql.begin(async(txSql) => {
2676+
await txSql`SET LOCAL idle_in_transaction_session_timeout = '1s'`
2677+
await new Promise(r => setTimeout(r, 2000))
2678+
try {
2679+
await txSql`SELECT 'should fail'`
2680+
txSqlSucceeded = true
2681+
} catch { /* ignore */ }
2682+
}).catch(() => { /* ignore */ })
2683+
await new Promise(r => setTimeout(r, 1000))
2684+
await sql.end()
2685+
return [false, txSqlSucceeded]
2686+
})

deno/src/connection.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,11 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
255255
}
256256

257257
function nextWrite(fn) {
258+
if (!socket) {
259+
// Connection was closed, cannot write
260+
chunk = nextWriteTimer = null
261+
return false
262+
}
258263
const x = socket.write(chunk, fn)
259264
nextWriteTimer !== null && clearImmediate(nextWriteTimer)
260265
chunk = nextWriteTimer = null
@@ -437,6 +442,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
437442
}
438443

439444
async function closed(hadError) {
445+
terminated = true // Mark connection as terminated to prevent further query attempts
440446
incoming = Buffer.alloc(0)
441447
remaining = 0
442448
incomings = null

deno/src/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,12 +238,13 @@ function Postgres(a, b) {
238238
let savepoints = 0
239239
, connection
240240
, prepare = null
241+
, closed = false
241242

242243
try {
243244
await sql.unsafe('begin ' + options.replace(/[^a-z ]/ig, ''), [], { onexecute }).execute()
244245
return await Promise.race([
245246
scope(connection, fn),
246-
new Promise((_, reject) => connection.onclose = reject)
247+
new Promise((_, reject) => connection.onclose = e => (closed = true, reject(e)))
247248
])
248249
} catch (error) {
249250
throw error
@@ -290,6 +291,8 @@ function Postgres(a, b) {
290291
}
291292

292293
function handler(q) {
294+
if (closed)
295+
return q.reject(Errors.connection('CONNECTION_CLOSED', options))
293296
q.catch(e => uncaughtError || (uncaughtError = e))
294297
c.queue === full
295298
? queries.push(q)

deno/tests/index.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2641,4 +2641,50 @@ t('query during copy error', async() => {
26412641
]
26422642
})
26432643

2644+
t('idle_in_transaction_session_timeout causes CONNECTION_CLOSED', { timeout: 5 }, async() => {
2645+
const sql = postgres(options)
2646+
const error = await sql.begin(async(txSql) => {
2647+
await txSql`SET LOCAL idle_in_transaction_session_timeout = '1s'`
2648+
await new Promise(r => setTimeout(r, 2000))
2649+
await txSql`SELECT 1`
2650+
}).catch(e => e)
2651+
await sql.end()
2652+
return [true, error.code === 'CONNECTION_CLOSED' || error.code === 'CONNECTION_DESTROYED']
2653+
})
2654+
2655+
t('txSql fails after idle_in_transaction_session_timeout even if callback continues', { timeout: 5 }, async() => {
2656+
const sql = postgres(options)
2657+
let failed = false
2658+
await sql.begin(async(txSql) => {
2659+
await txSql`SET LOCAL idle_in_transaction_session_timeout = '1s'`
2660+
await new Promise(r => setTimeout(r, 2000))
2661+
try { await txSql`SELECT 1` } catch (e) {
2662+
failed = e.code === 'CONNECTION_CLOSED' || e.code === 'CONNECTION_DESTROYED'
2663+
}
2664+
}).catch(() => { /* ignore */ })
2665+
await new Promise(r => setTimeout(r, 1000))
2666+
await sql.end()
2667+
return [true, failed]
2668+
})
2669+
2670+
t('txSql fails even when pool connection reconnects after idle timeout', { timeout: 10 }, async() => {
2671+
const sql = postgres({ ...options, max: 1 })
2672+
// Queue pool queries to trigger reconnect after connection closes
2673+
for (let i = 0; i < 3; i++)
2674+
setTimeout(() => sql`SELECT ${i}`.catch(() => { /* ignore */ }), 1000 + i * 100)
2675+
2676+
let txSqlSucceeded = false
2677+
await sql.begin(async(txSql) => {
2678+
await txSql`SET LOCAL idle_in_transaction_session_timeout = '1s'`
2679+
await new Promise(r => setTimeout(r, 2000))
2680+
try {
2681+
await txSql`SELECT 'should fail'`
2682+
txSqlSucceeded = true
2683+
} catch { /* ignore */ }
2684+
}).catch(() => { /* ignore */ })
2685+
await new Promise(r => setTimeout(r, 1000))
2686+
await sql.end()
2687+
return [false, txSqlSucceeded]
2688+
})
2689+
26442690
;globalThis.addEventListener("unload", () => Deno.exit(process.exitCode))

0 commit comments

Comments
 (0)