quosdolorem
Version:
The MongoDB Shell
77 lines (64 loc) • 2.73 kB
text/typescript
import { MongoshInternalError } from '@mongosh/errors';
import { Callback, CloseOptions, Connection, ConnectionPool } from 'mongodb';
let alreadyPatched = false;
// TODO: revisit whether we still need monkey patching in light of NODE-3263
export function ensureMongoNodeNativePatchesAreApplied(): void {
if (alreadyPatched) {
return;
}
patchConnectionPoolTracking();
alreadyPatched = true;
}
const poolToConnections = new Map<ConnectionPool, Set<Connection>>();
function patchConnectionPoolTracking(): void {
const connectionPoolPrototype: ConnectionPool = require('mongodb/lib/cmap/connection_pool').ConnectionPool.prototype;
if (!connectionPoolPrototype) {
throw new MongoshInternalError('Failed to setup connection handling');
}
const originalCheckOut = connectionPoolPrototype.checkOut;
const newCheckOut: typeof originalCheckOut = function(this: ConnectionPool, cb: Callback<Connection>): void {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const pool = this;
originalCheckOut.call(this, function(this: any, error, connection) {
if (connection) {
let connections = poolToConnections.get(pool);
if (!connections) {
connections = new Set<Connection>();
poolToConnections.set(pool, connections);
}
connections.add(connection);
}
cb.call(this, error, connection);
});
};
connectionPoolPrototype.checkOut = newCheckOut;
const originalCheckIn = connectionPoolPrototype.checkIn;
const newCheckIn: typeof originalCheckIn = function(this: ConnectionPool, connection: Connection): void {
if (connection) {
const connections = poolToConnections.get(this);
if (connections) {
connections.delete(connection);
}
}
originalCheckIn.call(this, connection);
};
connectionPoolPrototype.checkIn = newCheckIn;
const originalClose = connectionPoolPrototype.close;
const newClose: typeof originalClose = function(this: ConnectionPool, options: CloseOptions | Callback<void>, cb?: Callback<void>): void {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const pool = this;
const connections = poolToConnections.get(pool);
if (!pool.closed && connections && typeof options === 'object' && options.force) {
const originalCallback = cb;
cb = function(this: any, error: any, result: any) {
poolToConnections.delete(pool);
[...connections].forEach(c => c.destroy({ force: true }));
if (originalCallback) {
originalCallback.call(this, error, result);
}
};
}
originalClose.call(this, options as any, cb as any);
};
connectionPoolPrototype.close = newClose;
}