Skip to content

Commit

Permalink
feat: implemenet connection pooling
Browse files Browse the repository at this point in the history
pg-pool have removed `min` option (brianc/node-pg-pool#135). Our implementation partially implements the original pro-active pooling logic. However, unlike the original implementation, we only pool new queries when another query is complete. The benefit of this approach is that if the process is otherwise idle, there are no unnecessary sockets being kept. Equally, the moment a single query is issued, we ensure that we bring the pool size to the minimum number of connections expected.
  • Loading branch information
gajus committed Nov 10, 2019
1 parent 5d6fadf commit 151bc84
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 1 deletion.
57 changes: 56 additions & 1 deletion src/factories/createPool.js
Expand Up @@ -17,6 +17,54 @@ import Logger from '../Logger';
import bindPool from '../binders/bindPool';
import createClientConfiguration from './createClientConfiguration';

const createIdleConnection = (log, pool) => {
pool
.connect()
.then((connection) => {
return connection.release();
})
.catch((error) => {
log.error({
error: serializeError(error),
}, 'connection could not be added to the pool');
});
};

/**
* Attempts to keep a minimum of `minimumPoolSize` connections.
*
* We do not pro-actively create connections (e.g. using setInterval); instead we listen
* for when connections are removed and if there are less than `minimumPoolSize` already
* started connections, then we create new connections.
*
* As this process relies on pool being actively used to make new connections, (as opposed to using `setInterval`)
* we do not implement an explicit method of killing the connection pooling logic either;
* connections are killed after `idleTimeout`.
*/
const managePoolSize = (log, pool, minimumPoolSize: number) => {
let connectionCount = 0;

const provision = () => {
let missingConnectionCount = Math.max(0, minimumPoolSize - connectionCount);

while (missingConnectionCount-- > 0) {
createIdleConnection(log, pool);
}
};

pool.on('connect', () => {
connectionCount++;

provision();
});

pool.on('remove', () => {
connectionCount--;

provision();
});
};

/**
* @param connectionUri PostgreSQL [Connection URI](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING).
*/
Expand All @@ -37,7 +85,6 @@ export default (
poolConfiguration.connectionTimeoutMillis = clientConfiguration.connectionTimeout;
poolConfiguration.idleTimeoutMillis = clientConfiguration.idleTimeout;
poolConfiguration.max = clientConfiguration.maximumPoolSize;
poolConfiguration.min = clientConfiguration.minimumPoolSize;

if (clientConfiguration.connectionTimeout === 'DISABLE_TIMEOUT') {
poolConfiguration.connectionTimeout = 0;
Expand Down Expand Up @@ -91,6 +138,14 @@ export default (

const pool = new pg.Pool(poolConfiguration);

if (clientConfiguration.minimumPoolSize > 0) {
managePoolSize(
poolLog,
pool,
clientConfiguration.minimumPoolSize,
);
}

pool.slonik = {
poolId,
typeOverrides: null,
Expand Down
1 change: 1 addition & 0 deletions test/helpers/createPool.js
Expand Up @@ -37,6 +37,7 @@ export default (clientConfiguration: ClientConfigurationInputType = defaultConfi
};

const internalPool = {
_pulseQueue: () => {},
_remove: () => {},
connect: () => {
return connection;
Expand Down

0 comments on commit 151bc84

Please sign in to comment.