Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update PostgreSQL connection pool handling #2525

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/query/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Revert yargs version

### Changed
- Update how idle psql pool connections are handled (#2520)

## [2.14.0] - 2024-08-05
### Changed
- Update dependencies (#2518)
Expand Down
6 changes: 5 additions & 1 deletion packages/query/src/configure/configure.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@ import {debugPgClient} from './x-postgraphile/debugClient';
async function ensurePool(poolConfig: PoolConfig): Promise<Pool> {
const pgPool = new Pool(poolConfig);
try {
await pgPool.connect();
const pgClient = await pgPool.connect();
// Release the client back to the pool as it's no longer needed
pgClient.release();
} catch (e: any) {
if (JSON.stringify(e.message).includes(CONNECTION_SSL_ERROR_REGEX)) {
poolConfig.ssl = undefined;
// end the pool and recreate it without ssl
await pgPool.end();
return ensurePool(poolConfig);
}
}
Expand Down
21 changes: 21 additions & 0 deletions packages/query/src/graphql/graphql.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-3.0

import assert from 'assert';
import {setInterval} from 'timers';
import PgPubSub from '@graphile/pg-pubsub';
import {Module, OnModuleDestroy, OnModuleInit} from '@nestjs/common';
import {HttpAdapterHost} from '@nestjs/core';
Expand Down Expand Up @@ -127,6 +128,18 @@ export class GraphqlModule implements OnModuleInit, OnModuleDestroy {
}
}

private setupKeepAlive(pgClient) {
mpastecki marked this conversation as resolved.
Show resolved Hide resolved
setInterval(() => {
(async () => {
mpastecki marked this conversation as resolved.
Show resolved Hide resolved
try {
await pgClient.query('SELECT 1');
} catch (err) {
getLogger('db').error('Schema listener client keep-alive query failed: ', err);
}
})();
}, this.config.get('sl-keep-alive-interval'));
}

private async createServer() {
const app = this.httpAdapterHost.httpAdapter.getInstance();
const httpServer = this.httpAdapterHost.httpAdapter.getHttpServer();
Expand Down Expand Up @@ -165,6 +178,14 @@ export class GraphqlModule implements OnModuleInit, OnModuleDestroy {
const pgClient = await this.pgPool.connect();
await pgClient.query(`LISTEN "${hashName(dbSchema, 'schema_channel', '_metadata')}"`);

// Set up a keep-alive interval to prevent the connection from being killed
this.setupKeepAlive(pgClient);

pgClient.on('error', (err: Error) => {
getLogger('db').error('PostgreSQL schema listener client error: ', err);
process.exit(1);
});

pgClient.on('notification', (msg) => {
if (msg.payload === 'schema_updated') {
void this.schemaListener(dbSchema, options);
Expand Down
6 changes: 6 additions & 0 deletions packages/query/src/yargs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,12 @@ export function getYargsOption() {
type: 'boolean',
default: false,
},
'sl-keep-alive-interval': {
demandOption: false,
describe: 'Schema listener keep-alive interval in milliseconds',
type: 'number',
default: 180000,
},
});
}

Expand Down