@@ -107,7 +107,7 @@ export type ConnectionPoolEvents = {
107
107
*/
108
108
export class ConnectionPool extends TypedEventEmitter < ConnectionPoolEvents > {
109
109
closed : boolean ;
110
- options : Readonly < ConnectionPoolOptions > ;
110
+ options : Readonly < ConnectionPoolOptions & { maxConnecting : number } > ;
111
111
/** @internal */
112
112
[ kLogger ] : Logger ;
113
113
/** @internal */
@@ -199,6 +199,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
199
199
connectionType : Connection ,
200
200
maxPoolSize : options . maxPoolSize ?? 100 ,
201
201
minPoolSize : options . minPoolSize ?? 0 ,
202
+ maxConnecting : 2 ,
202
203
maxIdleTimeMS : options . maxIdleTimeMS ?? 0 ,
203
204
waitQueueTimeoutMS : options . waitQueueTimeoutMS ?? 0 ,
204
205
autoEncrypter : options . autoEncrypter ,
@@ -494,16 +495,29 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
494
495
}
495
496
496
497
function ensureMinPoolSize ( pool : ConnectionPool ) {
497
- if ( pool . closed || pool . options . minPoolSize === 0 ) {
498
+ const minPoolSize = pool . options . minPoolSize ;
499
+ if ( pool . closed || minPoolSize === 0 ) {
498
500
return ;
499
501
}
500
502
501
- const minPoolSize = pool . options . minPoolSize ;
502
- for ( let i = pool . totalConnectionCount ; i < minPoolSize ; ++ i ) {
503
- createConnection ( pool ) ;
503
+ if (
504
+ pool . totalConnectionCount < minPoolSize &&
505
+ pool . pendingConnectionCount < pool . options . maxConnecting
506
+ ) {
507
+ // NOTE: ensureMinPoolSize should not try to get all the pending
508
+ // connection permits because that potentially delays the availability of
509
+ // the connection to a checkout request
510
+ createConnection ( pool , ( err , connection ) => {
511
+ pool [ kPending ] -- ;
512
+ if ( ! err && connection ) {
513
+ pool [ kConnections ] . push ( connection ) ;
514
+ process . nextTick ( processWaitQueue , pool ) ;
515
+ }
516
+ pool [ kMinPoolSizeTimer ] = setTimeout ( ( ) => ensureMinPoolSize ( pool ) , 10 ) ;
517
+ } ) ;
518
+ } else {
519
+ pool [ kMinPoolSizeTimer ] = setTimeout ( ( ) => ensureMinPoolSize ( pool ) , 100 ) ;
504
520
}
505
-
506
- pool [ kMinPoolSizeTimer ] = setTimeout ( ( ) => ensureMinPoolSize ( pool ) , 10 ) ;
507
521
}
508
522
509
523
function connectionIsStale ( pool : ConnectionPool , connection : Connection ) {
@@ -521,7 +535,7 @@ function connectionIsIdle(pool: ConnectionPool, connection: Connection) {
521
535
return ! ! ( pool . options . maxIdleTimeMS && connection . idleTime > pool . options . maxIdleTimeMS ) ;
522
536
}
523
537
524
- function createConnection ( pool : ConnectionPool , callback ? : Callback < Connection > ) {
538
+ function createConnection ( pool : ConnectionPool , callback : Callback < Connection > ) {
525
539
const connectOptions : ConnectionOptions = {
526
540
...pool . options ,
527
541
id : pool [ kConnectionCounter ] . next ( ) . value ,
@@ -530,14 +544,16 @@ function createConnection(pool: ConnectionPool, callback?: Callback<Connection>)
530
544
} ;
531
545
532
546
pool [ kPending ] ++ ;
547
+ // This is our version of a "virtual" no-I/O connection as the spec requires
548
+ pool . emit (
549
+ ConnectionPool . CONNECTION_CREATED ,
550
+ new ConnectionCreatedEvent ( pool , { id : connectOptions . id } )
551
+ ) ;
552
+
533
553
connect ( connectOptions , ( err , connection ) => {
534
554
if ( err || ! connection ) {
535
- pool [ kPending ] -- ;
536
555
pool [ kLogger ] . debug ( `connection attempt failed with error [${ JSON . stringify ( err ) } ]` ) ;
537
- if ( typeof callback === 'function' ) {
538
- callback ( err ) ;
539
- }
540
-
556
+ callback ( err ) ;
541
557
return ;
542
558
}
543
559
@@ -553,8 +569,6 @@ function createConnection(pool: ConnectionPool, callback?: Callback<Connection>)
553
569
connection . on ( event , ( e : any ) => pool . emit ( event , e ) ) ;
554
570
}
555
571
556
- pool . emit ( ConnectionPool . CONNECTION_CREATED , new ConnectionCreatedEvent ( pool , connection ) ) ;
557
-
558
572
if ( pool . loadBalanced ) {
559
573
connection . on ( Connection . PINNED , pinType => pool [ kMetrics ] . markPinned ( pinType ) ) ;
560
574
connection . on ( Connection . UNPINNED , pinType => pool [ kMetrics ] . markUnpinned ( pinType ) ) ;
@@ -575,16 +589,8 @@ function createConnection(pool: ConnectionPool, callback?: Callback<Connection>)
575
589
connection . markAvailable ( ) ;
576
590
pool . emit ( ConnectionPool . CONNECTION_READY , new ConnectionReadyEvent ( pool , connection ) ) ;
577
591
578
- // if a callback has been provided, hand off the connection immediately
579
- if ( typeof callback === 'function' ) {
580
- callback ( undefined , connection ) ;
581
- return ;
582
- }
583
-
584
- // otherwise add it to the pool for later acquisition, and try to process the wait queue
585
- pool [ kConnections ] . push ( connection ) ;
586
- pool [ kPending ] -- ;
587
- process . nextTick ( processWaitQueue , pool ) ;
592
+ callback ( undefined , connection ) ;
593
+ return ;
588
594
} ) ;
589
595
}
590
596
@@ -642,44 +648,45 @@ function processWaitQueue(pool: ConnectionPool) {
642
648
}
643
649
}
644
650
645
- const maxPoolSize = pool . options . maxPoolSize ;
646
- if ( pool . waitQueueSize && ( maxPoolSize <= 0 || pool . totalConnectionCount < maxPoolSize ) ) {
651
+ const { maxPoolSize, maxConnecting } = pool . options ;
652
+ while (
653
+ pool . waitQueueSize > 0 &&
654
+ pool . pendingConnectionCount < maxConnecting &&
655
+ ( maxPoolSize === 0 || pool . totalConnectionCount < maxPoolSize )
656
+ ) {
657
+ const waitQueueMember = pool [ kWaitQueue ] . shift ( ) ;
658
+ if ( ! waitQueueMember || waitQueueMember [ kCancelled ] ) {
659
+ continue ;
660
+ }
647
661
createConnection ( pool , ( err , connection ) => {
648
- const waitQueueMember = pool [ kWaitQueue ] . shift ( ) ;
649
- if ( ! waitQueueMember || waitQueueMember [ kCancelled ] ) {
662
+ pool [ kPending ] -- ;
663
+ if ( waitQueueMember [ kCancelled ] ) {
650
664
if ( ! err && connection ) {
651
665
pool [ kConnections ] . push ( connection ) ;
652
- pool [ kPending ] -- ;
666
+ }
667
+ } else {
668
+ if ( err ) {
669
+ pool . emit (
670
+ ConnectionPool . CONNECTION_CHECK_OUT_FAILED ,
671
+ new ConnectionCheckOutFailedEvent ( pool , err )
672
+ ) ;
673
+ } else if ( connection ) {
674
+ pool [ kCheckedOut ] ++ ;
675
+ pool . emit (
676
+ ConnectionPool . CONNECTION_CHECKED_OUT ,
677
+ new ConnectionCheckedOutEvent ( pool , connection )
678
+ ) ;
653
679
}
654
680
655
- pool [ kProcessingWaitQueue ] = false ;
656
- return ;
657
- }
658
-
659
- if ( err ) {
660
- pool . emit (
661
- ConnectionPool . CONNECTION_CHECK_OUT_FAILED ,
662
- new ConnectionCheckOutFailedEvent ( pool , err )
663
- ) ;
664
- } else if ( connection ) {
665
- pool [ kCheckedOut ] ++ ;
666
- pool [ kPending ] -- ;
667
- pool . emit (
668
- ConnectionPool . CONNECTION_CHECKED_OUT ,
669
- new ConnectionCheckedOutEvent ( pool , connection )
670
- ) ;
671
- }
672
-
673
- if ( waitQueueMember . timer ) {
674
- clearTimeout ( waitQueueMember . timer ) ;
681
+ if ( waitQueueMember . timer ) {
682
+ clearTimeout ( waitQueueMember . timer ) ;
683
+ }
684
+ waitQueueMember . callback ( err , connection ) ;
675
685
}
676
- waitQueueMember . callback ( err , connection ) ;
677
- pool [ kProcessingWaitQueue ] = false ;
678
- process . nextTick ( ( ) => processWaitQueue ( pool ) ) ;
686
+ process . nextTick ( processWaitQueue , pool ) ;
679
687
} ) ;
680
- } else {
681
- pool [ kProcessingWaitQueue ] = false ;
682
688
}
689
+ pool [ kProcessingWaitQueue ] = false ;
683
690
}
684
691
685
692
/**
0 commit comments