From c9f4c44a6912e67a02bdcea8642352972883a115 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Thu, 4 Mar 2021 13:50:24 +0100 Subject: [PATCH 1/2] fix(service-provider-core): lower local server select timeout MONGOSH-362 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we connect to localhost, we don’t need to expect network delays and instead can assume fairly early that connecting does not succeed. --- .../src/uri-generator.spec.ts | 14 +++++++------- .../service-provider-core/src/uri-generator.ts | 10 +++++++++- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/service-provider-core/src/uri-generator.spec.ts b/packages/service-provider-core/src/uri-generator.spec.ts index 9d4789bf4f..557cafb54d 100644 --- a/packages/service-provider-core/src/uri-generator.spec.ts +++ b/packages/service-provider-core/src/uri-generator.spec.ts @@ -7,22 +7,22 @@ describe('uri-generator.generate-uri', () => { const options = { _: [] }; it('returns the default uri', () => { - expect(generateUri(options)).to.equal('mongodb://127.0.0.1:27017/?directConnection=true'); + expect(generateUri(options)).to.equal('mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000'); }); }); context('when no URI is provided', () => { it('handles host', () => { - expect(generateUri({ _: [], host: 'localhost' })).to.equal('mongodb://localhost:27017/?directConnection=true'); + expect(generateUri({ _: [], host: 'localhost' })).to.equal('mongodb://localhost:27017/?directConnection=true&serverSelectionTimeoutMS=2000'); }); it('handles port', () => { - expect(generateUri({ _: [], port: '27018' })).to.equal('mongodb://127.0.0.1:27018/?directConnection=true'); + expect(generateUri({ _: [], port: '27018' })).to.equal('mongodb://127.0.0.1:27018/?directConnection=true&serverSelectionTimeoutMS=2000'); }); it('handles both host and port', () => { - expect(generateUri({ _: [], host: 'localhost', port: '27018' })).to.equal('mongodb://localhost:27018/?directConnection=true'); + expect(generateUri({ _: [], host: 'localhost', port: '27018' })).to.equal('mongodb://localhost:27018/?directConnection=true&serverSelectionTimeoutMS=2000'); }); it('handles host with port included', () => { - expect(generateUri({ _: [], host: 'localhost:27018' })).to.equal('mongodb://localhost:27018/?directConnection=true'); + expect(generateUri({ _: [], host: 'localhost:27018' })).to.equal('mongodb://localhost:27018/?directConnection=true&serverSelectionTimeoutMS=2000'); }); it('throws if host has port AND port set to other value', () => { try { @@ -34,7 +34,7 @@ describe('uri-generator.generate-uri', () => { } }); it('handles host has port AND port set to equal value', () => { - expect(generateUri({ _: [], host: 'localhost:27018', port: '27018' })).to.equal('mongodb://localhost:27018/?directConnection=true'); + expect(generateUri({ _: [], host: 'localhost:27018', port: '27018' })).to.equal('mongodb://localhost:27018/?directConnection=true&serverSelectionTimeoutMS=2000'); }); }); @@ -228,7 +228,7 @@ describe('uri-generator.generate-uri', () => { const options = { _: [uri], port: '27018' }; it('uses the provided host with default port', () => { - expect(generateUri(options)).to.equal('mongodb://127.0.0.1:27018/foo?directConnection=true'); + expect(generateUri(options)).to.equal('mongodb://127.0.0.1:27018/foo?directConnection=true&serverSelectionTimeoutMS=2000'); }); }); diff --git a/packages/service-provider-core/src/uri-generator.ts b/packages/service-provider-core/src/uri-generator.ts index f80d98101e..9e05c96613 100644 --- a/packages/service-provider-core/src/uri-generator.ts +++ b/packages/service-provider-core/src/uri-generator.ts @@ -125,7 +125,15 @@ function generatePort(options: CliOptions): string { * gssapiServiceName?: string; // needs to go in URI */ function generateUri(options: CliOptions): string { - return generateUriNormalized(options).toString(); + const connectionString = generateUriNormalized(options); + if (connectionString.hosts.length === 1 && + ['localhost', '127.0.0.1'].includes(connectionString.hosts[0].split(':')[0])) { + const params = connectionString.searchParams; + if (!params.has('serverSelectionTimeoutMS')) { + params.set('serverSelectionTimeoutMS', '2000'); + } + } + return connectionString.toString(); } function generateUriNormalized(options: CliOptions): ConnectionString { const uri = options._?.[0]; From 650e282a38a78113974327907fa955004dcb8274 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Thu, 4 Mar 2021 15:20:47 +0100 Subject: [PATCH 2/2] fixup! fix(service-provider-core): lower local server select timeout MONGOSH-362 --- .../src/field-level-encryption.spec.ts | 4 +-- packages/shell-api/src/mongo.spec.ts | 4 +-- packages/shell-api/src/shell-api.spec.ts | 28 ++++++++++--------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/packages/shell-api/src/field-level-encryption.spec.ts b/packages/shell-api/src/field-level-encryption.spec.ts index 9f3d63b8e6..1e0d204de5 100644 --- a/packages/shell-api/src/field-level-encryption.spec.ts +++ b/packages/shell-api/src/field-level-encryption.spec.ts @@ -77,8 +77,8 @@ describe('Field Level Encryption', () => { expect((await toShellResult(keyVault.help)).type).to.equal('Help'); }); it('calls print function', async() => { - expect((await toShellResult(clientEncryption)).printable).to.equal('ClientEncryption class for mongodb://localhost:27017/test?directConnection=true'); - expect((await toShellResult(keyVault)).printable).to.equal('KeyVault class for mongodb://localhost:27017/test?directConnection=true'); + expect((await toShellResult(clientEncryption)).printable).to.equal('ClientEncryption class for mongodb://localhost:27017/test?directConnection=true&serverSelectionTimeoutMS=2000'); + expect((await toShellResult(keyVault)).printable).to.equal('KeyVault class for mongodb://localhost:27017/test?directConnection=true&serverSelectionTimeoutMS=2000'); }); it('has metadata type', async() => { expect((await toShellResult(clientEncryption)).type).to.equal('ClientEncryption'); diff --git a/packages/shell-api/src/mongo.spec.ts b/packages/shell-api/src/mongo.spec.ts index ab03104fbc..cacd43ae81 100644 --- a/packages/shell-api/src/mongo.spec.ts +++ b/packages/shell-api/src/mongo.spec.ts @@ -56,7 +56,7 @@ describe('Mongo', () => { describe('toShellResult', () => { const mongo = new Mongo({} as any, 'localhost:37017'); it('value', async() => { - expect((await toShellResult(mongo)).printable).to.equal('mongodb://localhost:37017/test?directConnection=true'); + expect((await toShellResult(mongo)).printable).to.equal('mongodb://localhost:37017/test?directConnection=true&serverSelectionTimeoutMS=2000'); }); it('type', async() => { expect((await toShellResult(mongo)).type).to.equal('Mongo'); @@ -561,7 +561,7 @@ describe('Mongo', () => { const expectedResult = { ChangeStreamCursor: 1 } as any; serviceProvider.watch.returns(expectedResult); const result = mongo.watch(); - expect(result).to.deep.equal(new ChangeStreamCursor(expectedResult, 'mongodb://localhost/?directConnection=true', mongo)); + expect(result).to.deep.equal(new ChangeStreamCursor(expectedResult, 'mongodb://localhost/?directConnection=true&serverSelectionTimeoutMS=2000', mongo)); expect(mongo._internalState.currentCursor).to.equal(result); }); diff --git a/packages/shell-api/src/shell-api.spec.ts b/packages/shell-api/src/shell-api.spec.ts index 6964cbe3d2..afcd325cd4 100644 --- a/packages/shell-api/src/shell-api.spec.ts +++ b/packages/shell-api/src/shell-api.spec.ts @@ -191,7 +191,7 @@ describe('ShellApi', () => { it('returns a new Mongo object', async() => { const m = await internalState.shellApi.Mongo('localhost:27017'); expect((await toShellResult(m)).type).to.equal('Mongo'); - expect(m._uri).to.equal('mongodb://localhost:27017/test?directConnection=true'); + expect(m._uri).to.equal('mongodb://localhost:27017/test?directConnection=true&serverSelectionTimeoutMS=2000'); }); it('fails for non-CLI', async() => { serviceProvider.platform = ReplPlatform.Browser; @@ -204,11 +204,11 @@ describe('ShellApi', () => { }); it('parses URI with mongodb://', async() => { const m = await internalState.shellApi.Mongo('mongodb://127.0.0.1:27017'); - expect(m._uri).to.equal('mongodb://127.0.0.1:27017/?directConnection=true'); + expect(m._uri).to.equal('mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000'); }); it('parses URI with just db', async() => { const m = await internalState.shellApi.Mongo('dbname'); - expect(m._uri).to.equal('mongodb://127.0.0.1:27017/dbname?directConnection=true'); + expect(m._uri).to.equal('mongodb://127.0.0.1:27017/dbname?directConnection=true&serverSelectionTimeoutMS=2000'); }); context('FLE', () => { [ @@ -226,7 +226,7 @@ describe('ShellApi', () => { } }); expect(serviceProvider.getNewConnection).to.have.been.calledOnceWithExactly( - 'mongodb://127.0.0.1:27017/dbname?directConnection=true', + 'mongodb://127.0.0.1:27017/dbname?directConnection=true&serverSelectionTimeoutMS=2000', { autoEncryption: { keyVaultClient: undefined, @@ -247,7 +247,7 @@ describe('ShellApi', () => { } }); expect(serviceProvider.getNewConnection).to.have.been.calledOnceWithExactly( - 'mongodb://127.0.0.1:27017/dbname?directConnection=true', + 'mongodb://127.0.0.1:27017/dbname?directConnection=true&serverSelectionTimeoutMS=2000', { autoEncryption: { keyVaultClient: undefined, @@ -267,7 +267,7 @@ describe('ShellApi', () => { keyVaultClient: mongo }); expect(serviceProvider.getNewConnection).to.have.been.calledOnceWithExactly( - 'mongodb://127.0.0.1:27017/dbname?directConnection=true', + 'mongodb://127.0.0.1:27017/dbname?directConnection=true&serverSelectionTimeoutMS=2000', { autoEncryption: { keyVaultClient: rawClientStub, @@ -291,7 +291,7 @@ describe('ShellApi', () => { keyVaultClient: m }); expect(serviceProvider.getNewConnection).to.have.been.calledOnceWithExactly( - 'mongodb://127.0.0.1:27017/dbname?directConnection=true', + 'mongodb://127.0.0.1:27017/dbname?directConnection=true&serverSelectionTimeoutMS=2000', { autoEncryption: { keyVaultClient: rc, @@ -354,7 +354,7 @@ describe('ShellApi', () => { bypassAutoEncryption: true }); expect(serviceProvider.getNewConnection).to.have.been.calledOnceWithExactly( - 'mongodb://127.0.0.1:27017/dbname?directConnection=true', + 'mongodb://127.0.0.1:27017/dbname?directConnection=true&serverSelectionTimeoutMS=2000', { autoEncryption: { keyVaultClient: undefined, @@ -372,7 +372,7 @@ describe('ShellApi', () => { serviceProvider.platform = ReplPlatform.CLI; const db = await internalState.shellApi.connect('localhost:27017', 'username', 'pwd'); expect((await toShellResult(db)).type).to.equal('Database'); - expect(db.getMongo()._uri).to.equal('mongodb://localhost:27017/test?directConnection=true'); + expect(db.getMongo()._uri).to.equal('mongodb://localhost:27017/test?directConnection=true&serverSelectionTimeoutMS=2000'); }); it('fails with no arg', async() => { serviceProvider.platform = ReplPlatform.CLI; @@ -456,7 +456,7 @@ describe('ShellApi', () => { it('returns a new Mongo object', async() => { const m = await internalState.context.Mongo('mongodb://127.0.0.1:27017'); expect((await toShellResult(m)).type).to.equal('Mongo'); - expect(m._uri).to.equal('mongodb://127.0.0.1:27017/?directConnection=true'); + expect(m._uri).to.equal('mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000'); }); it('fails for non-CLI', async() => { serviceProvider.platform = ReplPlatform.Browser; @@ -473,14 +473,16 @@ describe('ShellApi', () => { serviceProvider.platform = ReplPlatform.CLI; const db = await internalState.context.connect('mongodb://127.0.0.1:27017'); expect((await toShellResult(db)).type).to.equal('Database'); - expect(db.getMongo()._uri).to.equal('mongodb://127.0.0.1:27017/?directConnection=true'); + expect(db.getMongo()._uri).to.equal('mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000'); }); it('handles username/pwd', async() => { serviceProvider.platform = ReplPlatform.CLI; const db = await internalState.context.connect('mongodb://127.0.0.1:27017', 'username', 'pwd'); expect((await toShellResult(db)).type).to.equal('Database'); - expect(db.getMongo()._uri).to.equal('mongodb://127.0.0.1:27017/?directConnection=true'); - expect(serviceProvider.getNewConnection).to.have.been.calledOnceWithExactly('mongodb://127.0.0.1:27017/?directConnection=true', { auth: { username: 'username', password: 'pwd' } }); + expect(db.getMongo()._uri).to.equal('mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000'); + expect(serviceProvider.getNewConnection).to.have.been.calledOnceWithExactly( + 'mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000', + { auth: { username: 'username', password: 'pwd' } }); }); }); describe('version', () => {