From f399d3f816e2ace7117310ef832cc2a7307e5899 Mon Sep 17 00:00:00 2001 From: Nepomuk Crhonek <105591323+Nepomuk5665@users.noreply.github.com> Date: Sat, 24 Jan 2026 00:13:11 +0100 Subject: [PATCH 1/2] fix: iterate all servers in closeCheckedOutConnections() The method had a premature 'return' inside the for loop, which caused it to only close connections on the first server and exit immediately. This fix removes the return statement so all servers have their checked-out connections closed when MongoClient.close() is called. This bug would affect multi-server topologies (replica sets, sharded clusters) where only the first server's connections would be properly closed. --- src/sdam/topology.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sdam/topology.ts b/src/sdam/topology.ts index 2a158525fa..08ef6044bf 100644 --- a/src/sdam/topology.ts +++ b/src/sdam/topology.ts @@ -495,7 +495,7 @@ export class Topology extends TypedEventEmitter { closeCheckedOutConnections() { for (const server of this.s.servers.values()) { - return server.closeCheckedOutConnections(); + server.closeCheckedOutConnections(); } } From d2db45b39e0516e50839b7f29cd9ed4b0cbfdd5b Mon Sep 17 00:00:00 2001 From: Nepomuk Crhonek <105591323+Nepomuk5665@users.noreply.github.com> Date: Tue, 27 Jan 2026 09:53:45 +0100 Subject: [PATCH 2/2] test: improve ConnectionCheckedInEvent test to validate multi-server deployments - Remove 'single' topology restriction from metadata to support replicaset/sharded - Use readPreference: 'secondaryPreferred' to exercise connections to secondaries - Switch from insert to find operations to validate reads against secondaries --- .../connection_pool.test.ts | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/test/integration/connection-monitoring-and-pooling/connection_pool.test.ts b/test/integration/connection-monitoring-and-pooling/connection_pool.test.ts index d478b2bac1..d453dc39dd 100644 --- a/test/integration/connection-monitoring-and-pooling/connection_pool.test.ts +++ b/test/integration/connection-monitoring-and-pooling/connection_pool.test.ts @@ -72,7 +72,7 @@ describe('Connection Pool', function () { }); }); - const metadata: MongoDBMetadataUI = { requires: { mongodb: '>=4.4', topology: 'single' } }; + const metadata: MongoDBMetadataUI = { requires: { mongodb: '>=4.4' } }; describe('ConnectionCheckedInEvent', metadata, function () { let client: MongoClient; @@ -89,13 +89,13 @@ describe('Connection Pool', function () { configureFailPoint: 'failCommand', mode: 'alwaysOn', data: { - failCommands: ['insert'], + failCommands: ['find'], blockConnection: true, blockTimeMS: 500 } }); - client = this.configuration.newClient(); + client = this.configuration.newClient({}, { readPreference: 'secondaryPreferred' }); await client.connect(); await Promise.all(Array.from({ length: 100 }, () => client.db().command({ ping: 1 }))); }); @@ -120,37 +120,37 @@ describe('Connection Pool', function () { .on('connectionCheckedIn', pushToClientEvents) .on('connectionClosed', pushToClientEvents); - const inserts = Promise.allSettled([ - client.db('test').collection('test').insertOne({ a: 1 }), - client.db('test').collection('test').insertOne({ a: 1 }), - client.db('test').collection('test').insertOne({ a: 1 }) + const finds = Promise.allSettled([ + client.db('test').collection('test').findOne({ a: 1 }), + client.db('test').collection('test').findOne({ a: 1 }), + client.db('test').collection('test').findOne({ a: 1 }) ]); - // wait until all pings are pending on the server + // wait until all finds are pending on the server while (allClientEvents.filter(e => e.name === 'connectionCheckedOut').length < 3) { await sleep(1); } - const insertConnectionIds = allClientEvents + const findConnectionIds = allClientEvents .filter(e => e.name === 'connectionCheckedOut') .map(({ address, connectionId }) => `${address} + ${connectionId}`); await client.close(); - const insertCheckInAndCloses = allClientEvents + const findCheckInAndCloses = allClientEvents .filter(e => e.name === 'connectionCheckedIn' || e.name === 'connectionClosed') .filter(({ address, connectionId }) => - insertConnectionIds.includes(`${address} + ${connectionId}`) + findConnectionIds.includes(`${address} + ${connectionId}`) ); - expect(insertCheckInAndCloses).to.have.lengthOf(6); + expect(findCheckInAndCloses).to.have.lengthOf(6); // check that each check-in is followed by a close (not proceeded by one) - expect(insertCheckInAndCloses.map(e => e.name)).to.deep.equal( + expect(findCheckInAndCloses.map(e => e.name)).to.deep.equal( Array.from({ length: 3 }, () => ['connectionCheckedIn', 'connectionClosed']).flat(1) ); - await inserts; + await finds; } ); });