From cf532995c37bc710379879dbd91ab59472d763f3 Mon Sep 17 00:00:00 2001 From: Matt Broadstone Date: Tue, 23 Jul 2019 11:18:09 -0400 Subject: [PATCH] fix(replset): introduce a fixed-time server selection loop This is required because we are moving server selection to live outside of topologies. The legacy topologies would use the disconnectHandler to implement a form of server selection. --- lib/core/topologies/replset.js | 40 ++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/lib/core/topologies/replset.js b/lib/core/topologies/replset.js index b20e8aec31..44d2182297 100644 --- a/lib/core/topologies/replset.js +++ b/lib/core/topologies/replset.js @@ -19,6 +19,7 @@ const isRetryableWritesSupported = require('./shared').isRetryableWritesSupporte const relayEvents = require('../utils').relayEvents; const isRetryableError = require('../error').isRetryableError; const BSON = retrieveBSON(); +const calculateDurationInMs = require('../utils').calculateDurationInMs; // // States @@ -1110,19 +1111,36 @@ ReplSet.prototype.selectServer = function(selector, options, callback) { readPreference = options.readPreference || ReadPreference.primary; } - const server = this.s.replicaSetState.pickServer(readPreference); - if (server == null) { - callback(new MongoError('server selection failed')); - return; - } + let lastError; + const start = process.hrtime(); + const _selectServer = () => { + if (calculateDurationInMs(start) >= 10000) { + if (lastError != null) { + callback(lastError, null); + } else { + callback(new MongoError('Server selection timed out')); + } - if (!(server instanceof Server)) { - callback(server, null); - return; - } + return; + } + + const server = this.s.replicaSetState.pickServer(readPreference); + if (server == null) { + setTimeout(_selectServer, 1000); + return; + } + + if (!(server instanceof Server)) { + lastError = server; + setTimeout(_selectServer, 1000); + return; + } + + if (this.s.debug) this.emit('pickedServer', options.readPreference, server); + callback(null, server); + }; - if (this.s.debug) this.emit('pickedServer', options.readPreference, server); - callback(null, server); + _selectServer(); }; /**