Skip to content

Commit ff43e8d

Browse files
harrykaoWikiRik
andauthored
fix(postgres): invalidate connection after client-side timeout (sequelize#15144)
* Invalidate connection after client-side timeout. The `query_timeout` feature of the `pg` package helps handle stuck TCP connections more quickly and gracefully by implementing a client-side timeout: brianc/node-postgres#1713 Sequelize started passing this dialect-specific option through to `pg` here: sequelize#13258 I believe we also want to invalidate the connection when a client-side timeout occurs. We shouldn't try to reuse the stuck connection because...it's stuck. This PR updates the error handling code so that the connection is invalidated if the error matches the one thrown from here: https://github.com/brianc/node-postgres/blob/5538df6b446f4b4f921947b460fe38acb897e579/packages/pg/lib/client.js#L529 * Add comment with link to PR. * Add tests, shorten comment. * Skip tests for postgres-native. * Update src/dialects/postgres/query.js Co-authored-by: Rik Smale <[email protected]> Co-authored-by: Rik Smale <[email protected]>
1 parent a10a78c commit ff43e8d

File tree

2 files changed

+47
-1
lines changed

2 files changed

+47
-1
lines changed

src/dialects/postgres/query.js

+2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ export class PostgresQuery extends AbstractQuery {
5151
|| /Unable to set non-blocking to true/i.test(error)
5252
|| /SSL SYSCALL error: EOF detected/i.test(error)
5353
|| /Local: Authentication failure/i.test(error)
54+
// https://github.com/sequelize/sequelize/pull/15144
55+
|| error.message === 'Query read timeout'
5456
) {
5557
connection._invalid = true;
5658
}

test/integration/dialects/postgres/query.test.js

+45-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const expect = chai.expect;
66
const Support = require('../../support');
77

88
const dialect = Support.getTestDialect();
9-
const { DataTypes } = require('@sequelize/core');
9+
const { DatabaseError, DataTypes } = require('@sequelize/core');
1010

1111
if (dialect.startsWith('postgres')) {
1212
describe('[POSTGRES] Query', () => {
@@ -221,5 +221,49 @@ if (dialect.startsWith('postgres')) {
221221
order: [['order_0', 'DESC']],
222222
});
223223
});
224+
225+
describe('Connection Invalidation', () => {
226+
if (process.env.DIALECT === 'postgres-native') {
227+
// native driver doesn't support statement_timeout or query_timeout
228+
return;
229+
}
230+
231+
async function setUp(clientQueryTimeoutMs) {
232+
const sequelize = Support.createSequelizeInstance({
233+
dialectOptions: {
234+
statement_timeout: 500, // ms
235+
query_timeout: clientQueryTimeoutMs,
236+
},
237+
pool: {
238+
max: 1, // having only one helps us know whether the connection was invalidated
239+
idle: 60_000,
240+
},
241+
});
242+
243+
return { sequelize, originalPid: await getConnectionPid(sequelize) };
244+
}
245+
246+
async function getConnectionPid(sequelize) {
247+
const connection = await sequelize.connectionManager.getConnection();
248+
const pid = connection.processID;
249+
sequelize.connectionManager.releaseConnection(connection);
250+
251+
return pid;
252+
}
253+
254+
it('reuses connection after statement timeout', async () => {
255+
// client timeout > statement timeout means that the query should fail with a statement timeout
256+
const { sequelize, originalPid } = await setUp(10_000);
257+
await expect(sequelize.query('select pg_sleep(1)')).to.eventually.be.rejectedWith(DatabaseError, 'canceling statement due to statement timeout');
258+
expect(await getConnectionPid(sequelize)).to.equal(originalPid);
259+
});
260+
261+
it('invalidates connection after client-side query timeout', async () => {
262+
// client timeout < statement timeout means that the query should fail with a read timeout
263+
const { sequelize, originalPid } = await setUp(250);
264+
await expect(sequelize.query('select pg_sleep(1)')).to.eventually.be.rejectedWith(DatabaseError, 'Query read timeout');
265+
expect(await getConnectionPid(sequelize)).to.not.equal(originalPid);
266+
});
267+
});
224268
});
225269
}

0 commit comments

Comments
 (0)