@@ -66,6 +66,8 @@ const kMetrics = Symbol('metrics');
6666const kProcessingWaitQueue = Symbol ( 'processingWaitQueue' ) ;
6767/** @internal */
6868const kPoolState = Symbol ( 'poolState' ) ;
69+ /** @internal */
70+ const kWaitQueuePending = Symbol ( 'waitQueuePending' ) ;
6971
7072/** @public */
7173export interface ConnectionPoolOptions extends Omit < ConnectionOptions , 'id' | 'generation' > {
@@ -154,6 +156,8 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
154156 [ kMetrics ] : ConnectionPoolMetrics ;
155157 /** @internal */
156158 [ kProcessingWaitQueue ] : boolean ;
159+ /** @internal */
160+ [ kWaitQueuePending ] : number ;
157161
158162 /**
159163 * Emitted when the connection pool is created.
@@ -245,6 +249,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
245249 this [ kCancellationToken ] = new CancellationToken ( ) ;
246250 this [ kCancellationToken ] . setMaxListeners ( Infinity ) ;
247251 this [ kWaitQueue ] = new Denque ( ) ;
252+ this [ kWaitQueuePending ] = 0 ;
248253 this [ kMetrics ] = new ConnectionPoolMetrics ( ) ;
249254 this [ kProcessingWaitQueue ] = false ;
250255
@@ -396,6 +401,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
396401 if ( this . closed ) {
397402 return ;
398403 }
404+ this [ kWaitQueuePending ] = 0 ;
399405
400406 // handle load balanced case
401407 if ( this . loadBalanced && serviceId ) {
@@ -453,6 +459,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
453459 }
454460
455461 this [ kPoolState ] = PoolState . closed ;
462+ this [ kWaitQueuePending ] = 0 ;
456463 this . clearMinPoolSizeTimer ( ) ;
457464 this . processWaitQueue ( ) ;
458465
@@ -591,8 +598,8 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
591598 return ;
592599 }
593600
594- // The pool might have closed since we started trying to create a connection
595- if ( this . closed ) {
601+ // The pool might have been cleared or closed since we started trying to create a connection
602+ if ( this [ kPoolState ] !== PoolState . ready ) {
596603 this [ kPending ] -- ;
597604 connection . destroy ( { force : true } ) ;
598605 return ;
@@ -722,17 +729,29 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
722729 }
723730
724731 const { maxPoolSize, maxConnecting } = this . options ;
725- while (
726- this . waitQueueSize > 0 &&
727- this . pendingConnectionCount < maxConnecting &&
728- ( maxPoolSize === 0 || this . totalConnectionCount < maxPoolSize )
732+ for (
733+ let waitQueueIndex = this [ kWaitQueuePending ] ;
734+ waitQueueIndex < this . waitQueueSize ;
735+ waitQueueIndex ++
729736 ) {
730- const waitQueueMember = this [ kWaitQueue ] . shift ( ) ;
731- if ( ! waitQueueMember || waitQueueMember [ kCancelled ] ) {
732- continue ;
737+ if (
738+ this . pendingConnectionCount >= maxConnecting ||
739+ ( maxPoolSize > 0 && this . totalConnectionCount >= maxPoolSize )
740+ ) {
741+ break ;
733742 }
743+ this [ kWaitQueuePending ] ++ ;
734744 this . createConnection ( ( err , connection ) => {
735- if ( waitQueueMember [ kCancelled ] ) {
745+ // The > 0 guard is just a precaution against future refactors
746+ // Currently, the callback is invoked sync from createConnection
747+ // so we are guaranteed the pool is still ready at this point
748+ // however, if this changes to async, then it will be possible for the
749+ // queue to get cleared before we get here
750+ if ( this [ kWaitQueuePending ] > 0 ) {
751+ this [ kWaitQueuePending ] -- ;
752+ }
753+ const waitQueueMember = this [ kWaitQueue ] . shift ( ) ;
754+ if ( ! waitQueueMember || waitQueueMember [ kCancelled ] ) {
736755 if ( ! err && connection ) {
737756 this [ kConnections ] . push ( connection ) ;
738757 }
0 commit comments