@@ -107,7 +107,7 @@ export type ConnectionPoolEvents = {
107107 */
108108export class ConnectionPool extends TypedEventEmitter < ConnectionPoolEvents > {
109109 closed : boolean ;
110- options : Readonly < ConnectionPoolOptions > ;
110+ options : Readonly < ConnectionPoolOptions & { maxConnecting : number } > ;
111111 /** @internal */
112112 [ kLogger ] : Logger ;
113113 /** @internal */
@@ -199,6 +199,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
199199 connectionType : Connection ,
200200 maxPoolSize : options . maxPoolSize ?? 100 ,
201201 minPoolSize : options . minPoolSize ?? 0 ,
202+ maxConnecting : 2 ,
202203 maxIdleTimeMS : options . maxIdleTimeMS ?? 0 ,
203204 waitQueueTimeoutMS : options . waitQueueTimeoutMS ?? 0 ,
204205 autoEncrypter : options . autoEncrypter ,
@@ -494,16 +495,29 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
494495}
495496
496497function ensureMinPoolSize ( pool : ConnectionPool ) {
497- if ( pool . closed || pool . options . minPoolSize === 0 ) {
498+ const minPoolSize = pool . options . minPoolSize ;
499+ if ( pool . closed || minPoolSize === 0 ) {
498500 return ;
499501 }
500502
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 ) ;
504520 }
505-
506- pool [ kMinPoolSizeTimer ] = setTimeout ( ( ) => ensureMinPoolSize ( pool ) , 10 ) ;
507521}
508522
509523function connectionIsStale ( pool : ConnectionPool , connection : Connection ) {
@@ -521,7 +535,7 @@ function connectionIsIdle(pool: ConnectionPool, connection: Connection) {
521535 return ! ! ( pool . options . maxIdleTimeMS && connection . idleTime > pool . options . maxIdleTimeMS ) ;
522536}
523537
524- function createConnection ( pool : ConnectionPool , callback ? : Callback < Connection > ) {
538+ function createConnection ( pool : ConnectionPool , callback : Callback < Connection > ) {
525539 const connectOptions : ConnectionOptions = {
526540 ...pool . options ,
527541 id : pool [ kConnectionCounter ] . next ( ) . value ,
@@ -530,14 +544,16 @@ function createConnection(pool: ConnectionPool, callback?: Callback<Connection>)
530544 } ;
531545
532546 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+
533553 connect ( connectOptions , ( err , connection ) => {
534554 if ( err || ! connection ) {
535- pool [ kPending ] -- ;
536555 pool [ kLogger ] . debug ( `connection attempt failed with error [${ JSON . stringify ( err ) } ]` ) ;
537- if ( typeof callback === 'function' ) {
538- callback ( err ) ;
539- }
540-
556+ callback ( err ) ;
541557 return ;
542558 }
543559
@@ -553,8 +569,6 @@ function createConnection(pool: ConnectionPool, callback?: Callback<Connection>)
553569 connection . on ( event , ( e : any ) => pool . emit ( event , e ) ) ;
554570 }
555571
556- pool . emit ( ConnectionPool . CONNECTION_CREATED , new ConnectionCreatedEvent ( pool , connection ) ) ;
557-
558572 if ( pool . loadBalanced ) {
559573 connection . on ( Connection . PINNED , pinType => pool [ kMetrics ] . markPinned ( pinType ) ) ;
560574 connection . on ( Connection . UNPINNED , pinType => pool [ kMetrics ] . markUnpinned ( pinType ) ) ;
@@ -575,16 +589,8 @@ function createConnection(pool: ConnectionPool, callback?: Callback<Connection>)
575589 connection . markAvailable ( ) ;
576590 pool . emit ( ConnectionPool . CONNECTION_READY , new ConnectionReadyEvent ( pool , connection ) ) ;
577591
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 ;
588594 } ) ;
589595}
590596
@@ -642,44 +648,45 @@ function processWaitQueue(pool: ConnectionPool) {
642648 }
643649 }
644650
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+ }
647661 createConnection ( pool , ( err , connection ) => {
648- const waitQueueMember = pool [ kWaitQueue ] . shift ( ) ;
649- if ( ! waitQueueMember || waitQueueMember [ kCancelled ] ) {
662+ pool [ kPending ] -- ;
663+ if ( waitQueueMember [ kCancelled ] ) {
650664 if ( ! err && connection ) {
651665 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+ ) ;
653679 }
654680
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 ) ;
675685 }
676- waitQueueMember . callback ( err , connection ) ;
677- pool [ kProcessingWaitQueue ] = false ;
678- process . nextTick ( ( ) => processWaitQueue ( pool ) ) ;
686+ process . nextTick ( processWaitQueue , pool ) ;
679687 } ) ;
680- } else {
681- pool [ kProcessingWaitQueue ] = false ;
682688 }
689+ pool [ kProcessingWaitQueue ] = false ;
683690}
684691
685692/**
0 commit comments