Skip to content

Commit 89b77ed

Browse files
authored
fix: Change socket timeout default to 0 (#2572)
We make an implicit assumption with our default socket timeout that most operations will complete within the current default of 5min. This is not the case for services like Atlas Data Lake, which may regularly take far longer to complete operations. In general we can't make any assumptions about how long an operation will take to complete, and so the default socket timeout is now 0 (infinity) unless otherwise indicated. NODE-2835
1 parent 033b6e7 commit 89b77ed

17 files changed

+70
-44
lines changed

lib/cmap/connection.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class Connection extends EventEmitter {
3232
this.id = options.id;
3333
this.address = streamIdentifier(stream);
3434
this.bson = options.bson;
35-
this.socketTimeout = typeof options.socketTimeout === 'number' ? options.socketTimeout : 360000;
35+
this.socketTimeout = typeof options.socketTimeout === 'number' ? options.socketTimeout : 0;
3636
this.host = options.host || 'localhost';
3737
this.port = options.port || 27017;
3838
this.monitorCommands =

lib/core/connection/connect.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ function makeConnection(family, options, cancellationToken, _callback) {
263263
: typeof options.connectTimeoutMS === 'number'
264264
? options.connectTimeoutMS
265265
: 30000;
266-
const socketTimeout = typeof options.socketTimeout === 'number' ? options.socketTimeout : 360000;
266+
const socketTimeout = typeof options.socketTimeout === 'number' ? options.socketTimeout : 0;
267267
const rejectUnauthorized =
268268
typeof options.rejectUnauthorized === 'boolean' ? options.rejectUnauthorized : true;
269269

lib/core/connection/connection.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class Connection extends EventEmitter {
6969
* @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
7070
* @param {number} [options.keepAliveInitialDelay=120000] Initial delay before TCP keep alive enabled
7171
* @param {number} [options.connectionTimeout=30000] TCP Connection timeout setting
72-
* @param {number} [options.socketTimeout=360000] TCP Socket timeout setting
72+
* @param {number} [options.socketTimeout=0] TCP Socket timeout setting
7373
* @param {boolean} [options.promoteLongs] Convert Long values from the db into Numbers if they fit into 53 bits
7474
* @param {boolean} [options.promoteValues] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
7575
* @param {boolean} [options.promoteBuffers] Promotes Binary BSON values to native Node Buffers.
@@ -92,7 +92,7 @@ class Connection extends EventEmitter {
9292

9393
this.port = options.port || 27017;
9494
this.host = options.host || 'localhost';
95-
this.socketTimeout = typeof options.socketTimeout === 'number' ? options.socketTimeout : 360000;
95+
this.socketTimeout = typeof options.socketTimeout === 'number' ? options.socketTimeout : 0;
9696

9797
// These values are inspected directly in tests, but maybe not necessary to keep around
9898
this.keepAlive = typeof options.keepAlive === 'boolean' ? options.keepAlive : true;
@@ -316,8 +316,7 @@ class Connection extends EventEmitter {
316316
if (typeof options === 'function') (callback = options), (options = {});
317317

318318
const conn = this;
319-
const socketTimeout =
320-
typeof options.socketTimeout === 'number' ? options.socketTimeout : 360000;
319+
const socketTimeout = typeof options.socketTimeout === 'number' ? options.socketTimeout : 0;
321320
const bson = conn.options.bson;
322321
const query = new Query(bson, ns, command, {
323322
numberToSkip: 0,

lib/core/connection/pool.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ var _id = 0;
6363
* @param {number} [options.keepAliveInitialDelay=120000] Initial delay before TCP keep alive enabled
6464
* @param {boolean} [options.noDelay=true] TCP Connection no delay
6565
* @param {number} [options.connectionTimeout=30000] TCP Connection timeout setting
66-
* @param {number} [options.socketTimeout=360000] TCP Socket timeout setting
67-
* @param {number} [options.monitoringSocketTimeout=30000] TCP Socket timeout setting for replicaset monitoring socket
66+
* @param {number} [options.socketTimeout=0] TCP Socket timeout setting
67+
* @param {number} [options.monitoringSocketTimeout=0] TCP Socket timeout setting for replicaset monitoring socket
6868
* @param {boolean} [options.ssl=false] Use SSL for connection
6969
* @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function.
7070
* @param {Buffer} [options.ca] SSL Certificate store binary buffer
@@ -111,7 +111,7 @@ var Pool = function(topology, options) {
111111
minSize: 0,
112112
// socket settings
113113
connectionTimeout: 30000,
114-
socketTimeout: 360000,
114+
socketTimeout: 0,
115115
keepAlive: true,
116116
keepAliveInitialDelay: 120000,
117117
noDelay: true,

lib/core/topologies/replset.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -919,7 +919,7 @@ ReplSet.prototype.connect = function(options) {
919919
);
920920
});
921921

922-
// Error out as high availbility interval must be < than socketTimeout
922+
// Error out as high availability interval must be < than socketTimeout
923923
if (
924924
this.s.options.socketTimeout > 0 &&
925925
this.s.options.socketTimeout <= this.s.options.haInterval

lib/core/topologies/server.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ function topologyId(server) {
7575
* @param {number} [options.keepAliveInitialDelay=120000] Initial delay before TCP keep alive enabled
7676
* @param {boolean} [options.noDelay=true] TCP Connection no delay
7777
* @param {number} [options.connectionTimeout=30000] TCP Connection timeout setting
78-
* @param {number} [options.socketTimeout=360000] TCP Socket timeout setting
78+
* @param {number} [options.socketTimeout=0] TCP Socket timeout setting
7979
* @param {boolean} [options.ssl=false] Use SSL for connection
8080
* @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function.
8181
* @param {Buffer} [options.ca] SSL Certificate store binary buffer

lib/mongo_client.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ const validOptions = require('./operations/connect').validOptions;
9797
* @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
9898
* @param {number} [options.keepAliveInitialDelay=120000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
9999
* @param {number} [options.connectTimeoutMS=10000] How long to wait for a connection to be established before timing out
100-
* @param {number} [options.socketTimeoutMS=360000] How long a send or receive on a socket can take before timing out
100+
* @param {number} [options.socketTimeoutMS=0] How long a send or receive on a socket can take before timing out
101101
* @param {number} [options.family] Version of IP stack. Can be 4, 6 or null (default).
102102
* If null, will attempt to connect with IPv6, and will fall back to IPv4 on failure
103103
* @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
@@ -372,7 +372,7 @@ MongoClient.prototype.isConnected = function(options) {
372372
* @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
373373
* @param {number} [options.keepAliveInitialDelay=120000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
374374
* @param {number} [options.connectTimeoutMS=10000] How long to wait for a connection to be established before timing out
375-
* @param {number} [options.socketTimeoutMS=360000] How long a send or receive on a socket can take before timing out
375+
* @param {number} [options.socketTimeoutMS=0] How long a send or receive on a socket can take before timing out
376376
* @param {number} [options.family] Version of IP stack. Can be 4, 6 or null (default).
377377
* If null, will attempt to connect with IPv6, and will fall back to IPv4 on failure
378378
* @param {number} [options.reconnectTries=30] Server attempt to reconnect #times

lib/operations/connect.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ function connect(mongoClient, url, options, callback) {
290290
const _finalOptions = createUnifiedOptions(object, options);
291291

292292
// Check if we have connection and socket timeout set
293-
if (_finalOptions.socketTimeoutMS == null) _finalOptions.socketTimeoutMS = 360000;
293+
if (_finalOptions.socketTimeoutMS == null) _finalOptions.socketTimeoutMS = 0;
294294
if (_finalOptions.connectTimeoutMS == null) _finalOptions.connectTimeoutMS = 10000;
295295
if (_finalOptions.retryWrites == null) _finalOptions.retryWrites = true;
296296
if (_finalOptions.useRecoveryToken == null) _finalOptions.useRecoveryToken = true;
@@ -788,7 +788,7 @@ function translateOptions(options, translationOptions) {
788788
}
789789

790790
// Set the socket and connection timeouts
791-
if (options.socketTimeoutMS == null) options.socketTimeoutMS = 360000;
791+
if (options.socketTimeoutMS == null) options.socketTimeoutMS = 0;
792792
if (options.connectTimeoutMS == null) options.connectTimeoutMS = 10000;
793793

794794
if (!translationOptions.createServers) {

lib/topologies/mongos.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ var legalOptionNames = [
8484
* @param {boolean} [options.socketOptions.keepAlive=true] TCP Connection keep alive enabled
8585
* @param {number} [options.socketOptions.keepAliveInitialDelay=120000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
8686
* @param {number} [options.socketOptions.connectTimeoutMS=10000] How long to wait for a connection to be established before timing out
87-
* @param {number} [options.socketOptions.socketTimeoutMS=360000] How long a send or receive on a socket can take before timing out
87+
* @param {number} [options.socketOptions.socketTimeoutMS=0] How long a send or receive on a socket can take before timing out
8888
* @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit.
8989
* @param {boolean} [options.monitorCommands=false] Enable command monitoring for this topology
9090
* @fires Mongos#connect

lib/topologies/server.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ var legalOptionNames = [
8686
* @param {boolean} [options.socketOptions.keepAlive=true] TCP Connection keep alive enabled
8787
* @param {number} [options.socketOptions.keepAliveInitialDelay=120000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
8888
* @param {number} [options.socketOptions.connectTimeoutMS=10000] How long to wait for a connection to be established before timing out
89-
* @param {number} [options.socketOptions.socketTimeoutMS=360000] How long a send or receive on a socket can take before timing out
89+
* @param {number} [options.socketOptions.socketTimeoutMS=0] How long a send or receive on a socket can take before timing out
9090
* @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
9191
* @param {number} [options.reconnectInterval=1000] Server will wait # milliseconds between retries
9292
* @param {boolean} [options.monitoring=true] Triggers the server instance to call ismaster

test/functional/collection.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -799,7 +799,7 @@ describe('Collection', function() {
799799

800800
db.listCollections().toArray((err, documents) => {
801801
expect(err).to.not.exist;
802-
expect(documents.length > 1).to.be.true;
802+
expect(documents.length >= 1).to.be.true;
803803
let found = false;
804804

805805
documents.forEach(document => {

test/functional/mongo_client.test.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ describe('MongoClient', function() {
368368

369369
for (var i = 0; i < connections.length; i++) {
370370
test.equal(10000, connections[i].connectionTimeout);
371-
test.equal(360000, connections[i].socketTimeout);
371+
expect(connections[i].socketTimeout).to.equal(0);
372372
}
373373

374374
client.close();
@@ -518,7 +518,10 @@ describe('MongoClient', function() {
518518
{},
519519
{
520520
keepAlive: true,
521-
keepAliveInitialDelay: 100
521+
keepAliveInitialDelay: 100,
522+
// keepAliveInitialDelay is clamped to half the size of socketTimeout
523+
// if socketTimeout is less than keepAliveInitialDelay
524+
socketTimeout: 101
522525
}
523526
);
524527

test/functional/mongo_client_options.test.js

+17-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict';
2-
const test = require('./shared').assert,
3-
setupDatabase = require('./shared').setupDatabase,
4-
expect = require('chai').expect;
2+
const test = require('./shared').assert;
3+
const setupDatabase = require('./shared').setupDatabase;
4+
const expect = require('chai').expect;
55

66
describe('MongoClient Options', function() {
77
before(function() {
@@ -96,6 +96,20 @@ describe('MongoClient Options', function() {
9696
}
9797
});
9898

99+
it('should default socketTimeout to infinity', function(done) {
100+
const client = this.configuration.newClient();
101+
client.connect(() => {
102+
expect(client.s.options.socketTimeoutMS).to.deep.equal(0);
103+
const connections = client.topology.s.coreTopology
104+
? client.topology.s.coreTopology.connections()
105+
: [];
106+
for (const connection of connections) {
107+
expect(connection.socketTimeout).to.deep.equal(0);
108+
}
109+
client.close(done);
110+
});
111+
});
112+
99113
/**
100114
* @ignore
101115
*/

test/functional/operation_example.test.js

+9-7
Original file line numberDiff line numberDiff line change
@@ -3936,15 +3936,17 @@ describe('Operation Examples', function() {
39363936
// REMOVE-LINE done();
39373937
// REMOVE-LINE var db = client.db(configuration.db);
39383938
// BEGIN
3939+
expect(err).to.not.exist;
39393940
var db = client.db(configuration.db);
3940-
test.equal(null, err);
3941-
3942-
// Retry to get the collection, should work as it's now created
3943-
db.collections(function(err, collections) {
3944-
test.equal(null, err);
3945-
test.ok(collections.length > 0);
3941+
db.createCollection('example', err => {
3942+
expect(err).to.not.exist;
3943+
// Retry to get the collection, should work as it's now created
3944+
db.collections(function(err, collections) {
3945+
expect(err).to.not.exist;
3946+
test.ok(collections.length > 0);
39463947

3947-
client.close(done);
3948+
client.close(done);
3949+
});
39483950
});
39493951
});
39503952
// END

test/functional/operation_generators_example.test.js

+1
Original file line numberDiff line numberDiff line change
@@ -2931,6 +2931,7 @@ describe('Operation (Generators)', function() {
29312931
.newClient(configuration.writeConcernMax(), { poolSize: 1 })
29322932
.connect();
29332933
var db = client.db(configuration.db);
2934+
yield db.createCollection('example');
29342935
// LINE var MongoClient = require('mongodb').MongoClient,
29352936
// LINE co = require('co');
29362937
// LINE test = require('assert');

test/functional/operation_promises_example.test.js

+19-13
Original file line numberDiff line numberDiff line change
@@ -3149,22 +3149,28 @@ describe('Operation (Promises)', function() {
31493149
auto_reconnect: false
31503150
});
31513151

3152-
return client.connect().then(function(client) {
3153-
var db = client.db(configuration.db);
3154-
// LINE var MongoClient = require('mongodb').MongoClient,
3155-
// LINE test = require('assert');
3156-
// LINE const client = new MongoClient('mongodb://localhost:27017/test');
3157-
// LINE client.connect().then(() => {
3158-
// LINE var db = client.db('test);
3159-
// REPLACE configuration.writeConcernMax() WITH {w:1}
3160-
// REMOVE-LINE done();
3161-
// BEGIN
3162-
// Retry to get the collection, should work as it's now created
3163-
return db.collections().then(function(collections) {
3152+
return client
3153+
.connect()
3154+
.then(function(client) {
3155+
var db = client.db(configuration.db);
3156+
return db.createCollection('example');
3157+
})
3158+
.then(() => {
3159+
// LINE var MongoClient = require('mongodb').MongoClient,
3160+
// LINE test = require('assert');
3161+
// LINE const client = new MongoClient('mongodb://localhost:27017/test');
3162+
// LINE client.connect().then(() => {
3163+
// LINE var db = client.db('test);
3164+
// REPLACE configuration.writeConcernMax() WITH {w:1}
3165+
// REMOVE-LINE done();
3166+
// BEGIN
3167+
// Retry to get the collection, should work as it's now created
3168+
return client.db(configuration.db).collections();
3169+
})
3170+
.then(function(collections) {
31643171
test.ok(collections.length > 0);
31653172
return client.close();
31663173
});
3167-
});
31683174
// END
31693175
}
31703176
});

test/functional/replset_connection.test.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22
var f = require('util').format;
33
var test = require('./shared').assert;
4+
const expect = require('chai').expect;
45
var setupDatabase = require('./shared').setupDatabase;
56

67
var restartAndDone = function(configuration, done) {
@@ -595,7 +596,7 @@ describe.skip('ReplSet (Connection)', function() {
595596
var db = client.db(configuration.db);
596597

597598
test.equal(500, client.topology.connections()[0].connectionTimeout);
598-
test.equal(360000, client.topology.connections()[0].socketTimeout);
599+
expect(client.topology.connections()[0].socketTimeout).to.equal(0);
599600

600601
db.collection('replicaset_mongo_client_collection').update(
601602
{ a: 1 },

0 commit comments

Comments
 (0)