diff --git a/lib/operations/execute_operation.js b/lib/operations/execute_operation.js index f7fb0f53be..ca39083366 100644 --- a/lib/operations/execute_operation.js +++ b/lib/operations/execute_operation.js @@ -30,11 +30,25 @@ function executeOperation(topology, operation, callback) { throw new TypeError('This method requires a valid operation instance'); } - if (isUnifiedTopology(topology) && topology.shouldCheckForSessionSupport()) { - return selectServerForSessionSupport(topology, operation, callback); + const Promise = topology.s.promiseLibrary; + + let result; + if (typeof callback !== 'function') { + result = new Promise((resolve, reject) => { + callback = (err, res) => { + if (err) return reject(err); + resolve(res); + }; + }); } - const Promise = topology.s.promiseLibrary; + if (isUnifiedTopology(topology) && topology.shouldCheckForSessionSupport()) { + // Recursive call to executeOperation after a server selection + // shouldCheckForSessionSupport should return false after a server selection because + // there will be data bearing servers + selectServerForSessionSupport(topology, operation, callback); + return result; + } // The driver sessions spec mandates that we implicitly create sessions for operations // that are not explicitly provided with a session. @@ -45,20 +59,14 @@ function executeOperation(topology, operation, callback) { session = topology.startSession({ owner }); operation.session = session; } else if (operation.session.hasEnded) { - throw new MongoError('Use of expired sessions is not permitted'); + callback(new MongoError('Use of expired sessions is not permitted')); + return result; } - } else if (operation.session && operation.session.explicit) { - throw new MongoError('Current topology does not support sessions'); - } - - let result; - if (typeof callback !== 'function') { - result = new Promise((resolve, reject) => { - callback = (err, res) => { - if (err) return reject(err); - resolve(res); - }; - }); + } else if (operation.session && !topology.hasSessionSupport()) { + // If the user passed an explicit session and we are still, after server selection, + // trying to run against a topology that doesn't support sessions we error out. + callback(new MongoError('Current topology does not support sessions')); + return result; } function executeCallback(err, result) { @@ -78,7 +86,7 @@ function executeOperation(topology, operation, callback) { } else { operation.execute(executeCallback); } - } catch (e) { + } catch (error) { if (session && session.owner === owner) { session.endSession(); if (operation.session === session) { @@ -86,7 +94,7 @@ function executeOperation(topology, operation, callback) { } } - throw e; + callback(error); } return result; @@ -141,11 +149,6 @@ function executeWithServerSelection(topology, operation, callback) { callback(err, null); return; } - - if (serverSelectionOptions.session && topology.hasSessionSupport()) { - return callback(new MongoError('Current topology does not support sessions')); - } - const shouldRetryReads = topology.s.options.retryReads !== false && operation.session && @@ -165,28 +168,13 @@ function executeWithServerSelection(topology, operation, callback) { // TODO: This is only supported for unified topology, it should go away once // we remove support for legacy topology types. function selectServerForSessionSupport(topology, operation, callback) { - const Promise = topology.s.promiseLibrary; - - let result; - if (typeof callback !== 'function') { - result = new Promise((resolve, reject) => { - callback = (err, result) => { - if (err) return reject(err); - resolve(result); - }; - }); - } - topology.selectServer(ReadPreference.primaryPreferred, err => { if (err) { - callback(err); - return; + return callback(err); } executeOperation(topology, operation, callback); }); - - return result; } module.exports = executeOperation;