Skip to content

Commit

Permalink
feat(NODE-3750): make maxConnecting configurable (#3261)
Browse files Browse the repository at this point in the history
  • Loading branch information
dariakp authored May 25, 2022
1 parent f1887bf commit ee41447
Show file tree
Hide file tree
Showing 10 changed files with 195 additions and 6 deletions.
6 changes: 4 additions & 2 deletions src/cmap/connection_pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ export interface ConnectionPoolOptions extends Omit<ConnectionOptions, 'id' | 'g
maxPoolSize: number;
/** The minimum number of connections that MUST exist at any moment in a single connection pool. */
minPoolSize: number;
/** The maximum number of connections that may be in the process of being established concurrently by the connection pool. */
maxConnecting: number;
/** The maximum amount of time a connection should remain idle in the connection pool before being marked idle. */
maxIdleTimeMS: number;
/** The maximum amount of time operation execution should wait for a connection to become available. The default is 0 which means there is no limit. */
Expand Down Expand Up @@ -107,7 +109,7 @@ export type ConnectionPoolEvents = {
*/
export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
closed: boolean;
options: Readonly<ConnectionPoolOptions & { maxConnecting: number }>;
options: Readonly<ConnectionPoolOptions>;
/** @internal */
[kLogger]: Logger;
/** @internal */
Expand Down Expand Up @@ -199,7 +201,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
connectionType: Connection,
maxPoolSize: options.maxPoolSize ?? 100,
minPoolSize: options.minPoolSize ?? 0,
maxConnecting: 2,
maxConnecting: options.maxConnecting ?? 2,
maxIdleTimeMS: options.maxIdleTimeMS ?? 0,
waitQueueTimeoutMS: options.waitQueueTimeoutMS ?? 0,
autoEncrypter: options.autoEncrypter,
Expand Down
10 changes: 10 additions & 0 deletions src/connection_string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -856,6 +856,16 @@ export const OPTIONS = {
return new Logger('MongoClient', { loggerLevel: value as LoggerLevel });
}
},
maxConnecting: {
default: 2,
transform({ name, values: [value] }): number {
const maxConnecting = getUint(name, value);
if (maxConnecting === 0) {
throw new MongoInvalidArgumentError('maxConnecting must be > 0 if specified');
}
return maxConnecting;
}
},
maxIdleTimeMS: {
default: 0,
type: 'uint'
Expand Down
3 changes: 3 additions & 0 deletions src/mongo_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ export interface MongoClientOptions extends BSONSerializeOptions, SupportedNodeC
maxPoolSize?: number;
/** The minimum number of connections in the connection pool. */
minPoolSize?: number;
/** The maximum number of connections that may be in the process of being established concurrently by the connection pool. */
maxConnecting?: number;
/** The maximum number of milliseconds that a connection can remain idle in the pool before being removed and closed. */
maxIdleTimeMS?: number;
/** The maximum time in milliseconds that a thread can wait for a connection to become available. */
Expand Down Expand Up @@ -652,6 +654,7 @@ export interface MongoOptions
| 'keepAliveInitialDelay'
| 'localThresholdMS'
| 'logger'
| 'maxConnecting'
| 'maxIdleTimeMS'
| 'maxPoolSize'
| 'minPoolSize'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{
"version": 1,
"style": "integration",
"description": "custom maxConnecting is enforced",
"runOn": [
{
"minServerVersion": "4.4.0"
}
],
"failPoint": {
"configureFailPoint": "failCommand",
"mode": "alwaysOn",
"data": {
"failCommands": [
"isMaster",
"hello"
],
"closeConnection": false,
"blockConnection": true,
"blockTimeMS": 500
}
},
"poolOptions": {
"maxConnecting": 1,
"maxPoolSize": 2,
"waitQueueTimeoutMS": 5000
},
"operations": [
{
"name": "ready"
},
{
"name": "start",
"target": "thread1"
},
{
"name": "start",
"target": "thread2"
},
{
"name": "checkOut",
"thread": "thread1"
},
{
"name": "waitForEvent",
"event": "ConnectionCreated",
"count": 1
},
{
"name": "checkOut",
"thread": "thread2"
},
{
"name": "waitForEvent",
"event": "ConnectionReady",
"count": 2
}
],
"events": [
{
"type": "ConnectionCreated"
},
{
"type": "ConnectionReady"
},
{
"type": "ConnectionCreated"
},
{
"type": "ConnectionReady"
}
],
"ignore": [
"ConnectionCheckOutStarted",
"ConnectionCheckedIn",
"ConnectionCheckedOut",
"ConnectionClosed",
"ConnectionPoolCreated",
"ConnectionPoolReady"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
version: 1
style: integration
description: custom maxConnecting is enforced
runOn:
-
minServerVersion: "4.4.0"
failPoint:
configureFailPoint: failCommand
mode: "alwaysOn"
data:
failCommands: ["isMaster","hello"]
closeConnection: false
blockConnection: true
blockTimeMS: 500
poolOptions:
maxConnecting: 1
# gives opportunity for the checkout in thread2 to establish a new connection, which it must not do until thread1 establishes one
maxPoolSize: 2
waitQueueTimeoutMS: 5000
operations:
- name: ready
# thread1 exists to consume the single permit to open a connection,
# so that thread2 would be blocked acquiring a permit, which results in ordering its ConnectionCreated event after
# the ConnectionReady event from thread1.
- name: start
target: thread1
- name: start
target: thread2
- name: checkOut
thread: thread1
- name: waitForEvent
event: ConnectionCreated
count: 1
- name: checkOut
thread: thread2
- name: waitForEvent
event: ConnectionReady
count: 2
events:
- type: ConnectionCreated
- type: ConnectionReady
- type: ConnectionCreated
- type: ConnectionReady
ignore:
- ConnectionCheckOutStarted
- ConnectionCheckedIn
- ConnectionCheckedOut
- ConnectionClosed
- ConnectionPoolCreated
- ConnectionPoolReady
23 changes: 21 additions & 2 deletions test/spec/uri-options/connection-pool-options.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@
"tests": [
{
"description": "Valid connection pool options are parsed correctly",
"uri": "mongodb://example.com/?maxIdleTimeMS=50000&maxPoolSize=5&minPoolSize=3",
"uri": "mongodb://example.com/?maxIdleTimeMS=50000&maxPoolSize=5&minPoolSize=3&maxConnecting=1",
"valid": true,
"warning": false,
"hosts": null,
"auth": null,
"options": {
"maxIdleTimeMS": 50000,
"maxPoolSize": 5,
"minPoolSize": 3
"minPoolSize": 3,
"maxConnecting": 1
}
},
{
Expand Down Expand Up @@ -52,6 +53,24 @@
"options": {
"minPoolSize": 0
}
},
{
"description": "maxConnecting=0 causes a warning",
"uri": "mongodb://example.com/?maxConnecting=0",
"valid": true,
"warning": true,
"hosts": null,
"auth": null,
"options": {}
},
{
"description": "maxConnecting<0 causes a warning",
"uri": "mongodb://example.com/?maxConnecting=-1",
"valid": true,
"warning": true,
"hosts": null,
"auth": null,
"options": {}
}
]
}
24 changes: 22 additions & 2 deletions test/spec/uri-options/connection-pool-options.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
tests:
-
description: "Valid connection pool options are parsed correctly"
uri: "mongodb://example.com/?maxIdleTimeMS=50000&maxPoolSize=5&minPoolSize=3"
uri: "mongodb://example.com/?maxIdleTimeMS=50000&maxPoolSize=5&minPoolSize=3&maxConnecting=1"
valid: true
warning: false
hosts: ~
Expand All @@ -10,6 +10,7 @@ tests:
maxIdleTimeMS: 50000
maxPoolSize: 5
minPoolSize: 3
maxConnecting: 1
-
description: "Non-numeric maxIdleTimeMS causes a warning"
uri: "mongodb://example.com/?maxIdleTimeMS=invalid"
Expand Down Expand Up @@ -45,4 +46,23 @@ tests:
hosts: ~
auth: ~
options:
minPoolSize: 0
minPoolSize: 0

-
description: "maxConnecting=0 causes a warning"
uri: "mongodb://example.com/?maxConnecting=0"
valid: true
warning: true
hosts: ~
auth: ~
options: {}

-
description: "maxConnecting<0 causes a warning"
uri: "mongodb://example.com/?maxConnecting=-1"
valid: true
warning: true
hosts: ~
auth: ~
options: {}

1 change: 1 addition & 0 deletions test/tools/cmap_spec_runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type CmapOperation =
type CmapPoolOptions = {
maxPoolSize?: number;
minPoolSize?: number;
maxConnecting?: number;
maxIdleTimeMS?: number;
waitQueueTimeoutMS?: number;
};
Expand Down
1 change: 1 addition & 0 deletions test/tools/uri_spec_runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ export function executeUriValidationTest(

//** DIRECTLY MAPPED OPTIONS **/
case 'zlibCompressionLevel':
case 'maxConnecting':
case 'maxPoolSize':
case 'minPoolSize':
case 'connectTimeoutMS':
Expand Down
2 changes: 2 additions & 0 deletions test/unit/mongo_client.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ describe('MongoOptions', function () {
localThresholdMS: 3,
logger: new Logger('Testing!'),
loggerLevel: 'info',
maxConnecting: 5,
maxIdleTimeMS: 3,
maxPoolSize: 2,
maxStalenessSeconds: 3,
Expand Down Expand Up @@ -162,6 +163,7 @@ describe('MongoOptions', function () {
'heartbeatFrequencyMS=2',
'journal=true',
'localThresholdMS=2',
'maxConnecting=5',
'maxIdleTimeMS=2',
'maxPoolSize=4',
'maxStalenessSeconds=2',
Expand Down

0 comments on commit ee41447

Please sign in to comment.