diff --git a/lib/mongo_client.js b/lib/mongo_client.js index 62b0b0da58..f8aaa9d589 100644 --- a/lib/mongo_client.js +++ b/lib/mongo_client.js @@ -194,7 +194,8 @@ function MongoClient(url, options) { url: url, options: options || {}, promiseLibrary: null, - dbCache: {} + dbCache: {}, + sessions: [] }; // Get the promiseLibrary @@ -308,6 +309,14 @@ MongoClient.prototype.close = function(force, callback) { // Remove listeners after emit self.removeAllListeners('close'); + // If we have sessions, we want to send a single `endSessions` command for them, + // and then individually clean them up. They will be removed from the internal state + // when they emit their `ended` events. + if (this.s.sessions.length) { + this.topology.endSessions(this.s.sessions); + this.s.sessions.forEach(session => session.endSession({ skipCommand: true })); + } + // Callback after next event loop tick if (typeof callback === 'function') return process.nextTick(function() { @@ -481,7 +490,13 @@ MongoClient.prototype.startSession = function(options) { throw new MongoError('Current topology does not support sessions'); } - return this.topology.startSession(options); + const session = this.topology.startSession(options); + session.once('ended', () => { + this.s.sessions = this.s.sessions.filter(s => s.equals(session)); + }); + + this.s.sessions.push(session); + return session; }; var mergeOptions = function(target, source, flatten) { diff --git a/lib/topologies/topology_base.js b/lib/topologies/topology_base.js index c0efc4f4da..96d6d3dcc1 100644 --- a/lib/topologies/topology_base.js +++ b/lib/topologies/topology_base.js @@ -368,6 +368,10 @@ class TopologyBase extends EventEmitter { return this.s.coreTopology.getServer(options); } + endSessions(sessions, callback) { + return this.s.coreTopology.endSessions(sessions, callback); + } + /** * Unref all sockets * @method diff --git a/package.json b/package.json index 7fe5f3287d..79a0a06a3c 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "official" ], "dependencies": { - "mongodb-core": "mongodb-js/mongodb-core#8aaac8bcc7bdc02bf8bf4b03337a0af71ddc513e" + "mongodb-core": "mongodb-js/mongodb-core#6510d7d3d82d84cc0811a853355deaa918b96941" }, "devDependencies": { "betterbenchmarks": "^0.1.0", diff --git a/test/functional/sessions_tests.js b/test/functional/sessions_tests.js new file mode 100644 index 0000000000..4b846bde70 --- /dev/null +++ b/test/functional/sessions_tests.js @@ -0,0 +1,48 @@ +'use strict'; +const expect = require('chai').expect, + mongo = require('../..'), + setupDatabase = require('./shared').setupDatabase; + +const ignoredCommands = ['ismaster']; +const test = { commands: { started: [], succeeded: [] } }; +describe('Sessions', function() { + before(function() { + return setupDatabase(this.configuration); + }); + + afterEach(() => test.listener.uninstrument()); + beforeEach(function() { + test.commands = { started: [], succeeded: [] }; + test.listener = mongo.instrument(err => expect(err).to.be.null); + test.listener.on('started', event => { + if (ignoredCommands.indexOf(event.commandName) === -1) test.commands.started.push(event); + }); + + test.listener.on('succeeded', event => { + if (ignoredCommands.indexOf(event.commandName) === -1) test.commands.succeeded.push(event); + }); + + test.client = this.configuration.newClient({ w: 1 }, { poolSize: 1, auto_reconnect: false }); + return test.client.connect(); + }); + + it('should send endSessions for multiple sessions', { + metadata: { requires: { topology: ['single'] } }, + test: function(done) { + var client = this.configuration.newClient({ w: 1 }, { poolSize: 1, auto_reconnect: false }); + client.connect((err, client) => { + let sessions = [client.startSession(), client.startSession()].map(s => s.id); + + client.close(err => { + expect(err).to.not.exist; + expect(test.commands.started).to.have.length(1); + expect(test.commands.started[0].commandName).to.equal('endSessions'); + expect(test.commands.started[0].command.endSessions).to.include.deep.members(sessions); + + expect(client.s.sessions).to.have.length(0); + done(); + }); + }); + } + }); +}); diff --git a/yarn.lock b/yarn.lock index 55645fd494..8a37756ed7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2115,9 +2115,9 @@ mongodb-core@mongodb-js/mongodb-core#3.0.0: bson "~1.0.4" require_optional "^1.0.1" -mongodb-core@mongodb-js/mongodb-core#8aaac8bcc7bdc02bf8bf4b03337a0af71ddc513e: +mongodb-core@mongodb-js/mongodb-core#6510d7d3d82d84cc0811a853355deaa918b96941: version "3.0.0-beta2" - resolved "https://codeload.github.com/mongodb-js/mongodb-core/tar.gz/8aaac8bcc7bdc02bf8bf4b03337a0af71ddc513e" + resolved "https://codeload.github.com/mongodb-js/mongodb-core/tar.gz/6510d7d3d82d84cc0811a853355deaa918b96941" dependencies: bson "~1.0.4" require_optional "^1.0.1"