-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: allow client connect after close #2581
Changes from 3 commits
8ca579c
f7ca2ff
c5e0309
4fe0911
4c113dd
09dde51
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -346,19 +346,29 @@ export class MongoClient extends EventEmitter implements OperationParent { | |
const force = typeof forceOrCallback === 'boolean' ? forceOrCallback : false; | ||
|
||
return maybePromise(callback, cb => { | ||
const completeClose = (err?: AnyError) => { | ||
// clear out references to old topology | ||
this.topology = undefined; | ||
this.s.dbCache = new Map(); | ||
this.s.sessions = new Set(); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Per a discussion from #2355, we don't restore
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is fine for today. There's another unit of work here in the future (after the |
||
cb(err); | ||
}; | ||
|
||
if (this.topology == null) { | ||
return cb(); | ||
completeClose(); | ||
return; | ||
} | ||
|
||
const topology = this.topology; | ||
topology.close({ force }, err => { | ||
const autoEncrypter = topology.s.options.autoEncrypter; | ||
if (!autoEncrypter) { | ||
cb(err); | ||
completeClose(err); | ||
return; | ||
} | ||
|
||
autoEncrypter.teardown(force, err2 => cb(err || err2)); | ||
autoEncrypter.teardown(force, err2 => completeClose(err || err2)); | ||
}); | ||
}); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -197,6 +197,11 @@ export function connect( | |
throw new Error('no callback function provided'); | ||
} | ||
|
||
// Has a connection already been established? | ||
if (mongoClient.topology && mongoClient.topology.isConnected()) { | ||
throw new Error(`'connect' cannot be called when already connected`); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's not use plain |
||
} | ||
|
||
let didRequestAuthentication = false; | ||
const logger = new Logger('MongoClient', options); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
const test = require('./shared').assert, | ||
setupDatabase = require('./shared').setupDatabase, | ||
expect = require('chai').expect; | ||
const withClient = require('./shared').withClient; | ||
|
||
describe('Connection', function () { | ||
before(function () { | ||
|
@@ -273,4 +274,32 @@ describe('Connection', function () { | |
done(); | ||
} | ||
}); | ||
|
||
it( | ||
'should be able to connect again after close', | ||
withClient(function (client, done) { | ||
expect(client.isConnected()).to.be.true; | ||
|
||
const collection = () => client.db('testReconnect').collection('test'); | ||
mbroadst marked this conversation as resolved.
Show resolved
Hide resolved
|
||
collection().insertOne({ a: 1 }, (err, result) => { | ||
expect(err).to.not.exist; | ||
expect(result).to.exist; | ||
|
||
client.close(err => { | ||
expect(err).to.not.exist; | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd add |
||
client.connect(err => { | ||
expect(err).to.not.exist; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And another |
||
|
||
collection().insertOne({ b: 2 }, (err, result) => { | ||
expect(err).to.not.exist; | ||
expect(result).to.exist; | ||
expect(client.topology.isDestroyed()).to.be.false; | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}) | ||
); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -123,7 +123,7 @@ describe('Sessions', function () { | |
// verify that the `endSessions` command was sent | ||
const lastCommand = test.commands.started[test.commands.started.length - 1]; | ||
expect(lastCommand.commandName).to.equal('endSessions'); | ||
expect(client.topology.s.sessionPool.sessions).to.have.length(0); | ||
expect(client.topology).to.not.exist; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what's going on with the changes in this file? It looks like we're losing coverage There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As part of closing the I agree it's not the best but it seems like we have to set the topology to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm. I think an implicit part of this work is that Have you tried not resetting There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, you're right, it is possible to not set Update: decided against making these changes because of the refactor required to re-connect topologies may be too much work for this ticket. |
||
}); | ||
}); | ||
}); | ||
|
@@ -143,7 +143,7 @@ describe('Sessions', function () { | |
// verify that the `endSessions` command was sent | ||
const lastCommand = test.commands.started[test.commands.started.length - 1]; | ||
expect(lastCommand.commandName).to.equal('endSessions'); | ||
expect(client.topology.s.sessionPool.sessions).to.have.length(0); | ||
expect(client.topology).to.not.exist; | ||
}); | ||
}); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: naming of
completeClose
, perhaps something likeresetState
is more apt?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had a small offline discussion. Leaning towards leaving this as-is because
completeClose
both resets the state and calls the callback. Does anyone else have thoughts on this?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with
completeClose
, it's also a pattern we use elsewhere