Skip to content

Commit 4472060

Browse files
committed
fix: acquire with signal tests
Signed-off-by: ferhat elmas <elmas.ferhat@gmail.com>
1 parent 5bad4ff commit 4472060

1 file changed

Lines changed: 64 additions & 2 deletions

File tree

src/test/pg-connection.test.ts

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ describe('Pg database foundation', () => {
2929
}
3030
}
3131

32-
async function createConnection() {
32+
async function createConnection(overrides?: Partial<TenantConnectionOptions>) {
3333
const superUser = await getServiceKeyUser(tenantId)
34-
const settings = createConnectionSettings(superUser)
34+
const settings = createConnectionSettings(superUser, overrides)
3535

3636
const pool = new PgPoolStrategy(settings)
3737
const connection = new PgTenantConnection(pool, settings)
@@ -206,6 +206,68 @@ describe('Pg database foundation', () => {
206206
}
207207
})
208208

209+
it('releases the pending client unused when acquisition is aborted on an exhausted pool', async () => {
210+
const { pool } = await createConnection({ maxConnections: 1 })
211+
212+
try {
213+
const holder = await pool.acquire().beginTransaction()
214+
215+
try {
216+
const controller = new AbortController()
217+
const pending = pool.acquire().beginTransaction({ signal: controller.signal })
218+
controller.abort()
219+
220+
await expect(pending).rejects.toMatchObject({
221+
name: 'AbortError',
222+
code: 'ABORT_ERR',
223+
message: 'Query was aborted',
224+
})
225+
226+
expect(pool.getPoolStats()).toEqual({ total: 1, used: 1 })
227+
} finally {
228+
await holder.rollback()
229+
}
230+
231+
await new Promise((resolve) => setImmediate(resolve))
232+
expect(pool.getPoolStats()).toEqual({ total: 1, used: 0 })
233+
234+
const result = await pool.acquire().query<{ n: number }>('SELECT 1 AS n')
235+
expect(result.rows[0].n).toBe(1)
236+
expect(pool.getPoolStats()).toEqual({ total: 1, used: 0 })
237+
} finally {
238+
await pool.destroy()
239+
}
240+
})
241+
242+
it('destroys the client instead of returning it to the pool when a query is aborted mid-flight', async () => {
243+
const { pool } = await createConnection()
244+
const controller = new AbortController()
245+
246+
try {
247+
const query = pool.acquire().query('SELECT pg_sleep(10)', {
248+
signal: controller.signal,
249+
})
250+
const abortTimeout = setTimeout(() => controller.abort(), 50)
251+
252+
try {
253+
await expect(query).rejects.toMatchObject({
254+
name: 'AbortError',
255+
code: 'ABORT_ERR',
256+
})
257+
} finally {
258+
clearTimeout(abortTimeout)
259+
}
260+
261+
expect(pool.getPoolStats()).toEqual({ total: 0, used: 0 })
262+
263+
const result = await pool.acquire().query<{ n: number }>('SELECT 1 AS n')
264+
expect(result.rows[0].n).toBe(1)
265+
expect(pool.getPoolStats()).toEqual({ total: 1, used: 0 })
266+
} finally {
267+
await pool.destroy()
268+
}
269+
})
270+
209271
it('reuses cached pg tenant pools for cacheable settings', async () => {
210272
const superUser = await getServiceKeyUser(tenantId)
211273
const settings = createConnectionSettings(superUser, {

0 commit comments

Comments
 (0)