Skip to content

Commit 2014b7b

Browse files
committed
feat: support connection establishment cancellation
This allows us to cancel in-flight connection establishment in cases where connections might be blackholed, or waiting for an attempt to time out in `connectTimeoutMS` NODE-2363
1 parent 8a07893 commit 2014b7b

File tree

2 files changed

+29
-4
lines changed

2 files changed

+29
-4
lines changed

lib/core/connection/connect.js

+16-4
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,19 @@ const MIN_SUPPORTED_WIRE_VERSION = WIRE_CONSTANTS.MIN_SUPPORTED_WIRE_VERSION;
1414
const MIN_SUPPORTED_SERVER_VERSION = WIRE_CONSTANTS.MIN_SUPPORTED_SERVER_VERSION;
1515
let AUTH_PROVIDERS;
1616

17-
function connect(options, callback) {
17+
function connect(options, cancellationToken, callback) {
18+
if (typeof cancellationToken === 'function') {
19+
callback = cancellationToken;
20+
cancellationToken = undefined;
21+
}
22+
1823
const ConnectionType = options && options.connectionType ? options.connectionType : Connection;
1924
if (AUTH_PROVIDERS == null) {
2025
AUTH_PROVIDERS = defaultAuthProviders(options.bson);
2126
}
2227

2328
const family = options.family !== void 0 ? options.family : 0;
24-
makeConnection(family, options, (err, socket) => {
29+
makeConnection(family, options, cancellationToken, (err, socket) => {
2530
if (err) {
2631
callback(err, socket); // in the error case, `socket` is the originating error event name
2732
return;
@@ -219,7 +224,7 @@ function parseSslOptions(family, options) {
219224
}
220225

221226
const SOCKET_ERROR_EVENTS = new Set(['error', 'close', 'timeout', 'parseError']);
222-
function makeConnection(family, options, _callback) {
227+
function makeConnection(family, options, cancellationToken, _callback) {
223228
const useSsl = typeof options.ssl === 'boolean' ? options.ssl : false;
224229
const keepAlive = typeof options.keepAlive === 'boolean' ? options.keepAlive : true;
225230
let keepAliveInitialDelay =
@@ -240,6 +245,7 @@ function makeConnection(family, options, _callback) {
240245
if (err && socket) {
241246
socket.destroy();
242247
}
248+
243249
_callback(err, ret);
244250
};
245251

@@ -264,7 +270,7 @@ function makeConnection(family, options, _callback) {
264270
return err => {
265271
SOCKET_ERROR_EVENTS.forEach(event => socket.removeAllListeners(event));
266272
socket.removeListener('connect', connectHandler);
267-
callback(connectionFailureError(eventName, err), eventName);
273+
callback(connectionFailureError(eventName, err));
268274
};
269275
}
270276

@@ -279,6 +285,10 @@ function makeConnection(family, options, _callback) {
279285
}
280286

281287
SOCKET_ERROR_EVENTS.forEach(event => socket.once(event, errorHandler(event)));
288+
if (cancellationToken) {
289+
cancellationToken.once('cancel', errorHandler('cancel'));
290+
}
291+
282292
socket.once('connect', connectHandler);
283293
}
284294

@@ -359,6 +369,8 @@ function connectionFailureError(type, err) {
359369
return new MongoNetworkError(`connection timed out`);
360370
case 'close':
361371
return new MongoNetworkError(`connection closed`);
372+
case 'cancel':
373+
return new MongoNetworkError(`connection establishment was cancelled`);
362374
default:
363375
return new MongoNetworkError(`unknown network error`);
364376
}

test/unit/core/connect.test.js

+13
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,19 @@ describe('Connect Tests', function() {
129129
}
130130
);
131131

132+
it('should allow a cancellaton token', function(done) {
133+
const cancellationToken = new EventEmitter();
134+
setTimeout(() => cancellationToken.emit('cancel'), 100);
135+
// set no response handler for mock server, effecively blackhole requests
136+
137+
connect(test.connectOptions, cancellationToken, (err, conn) => {
138+
expect(err).to.exist;
139+
expect(err).to.match(/connection establishment was cancelled/);
140+
expect(conn).to.not.exist;
141+
done();
142+
});
143+
});
144+
132145
describe('runCommand', function() {
133146
const metadata = { requires: { topology: 'single' } };
134147
class MockConnection extends EventEmitter {

0 commit comments

Comments
 (0)