@@ -17,8 +17,7 @@ import {
17
17
} from '../constants' ;
18
18
import {
19
19
type AnyError ,
20
- MONGODB_ERROR_CODES ,
21
- MongoError ,
20
+ type MongoError ,
22
21
MongoInvalidArgumentError ,
23
22
MongoMissingCredentialsError ,
24
23
MongoNetworkError ,
@@ -27,7 +26,14 @@ import {
27
26
} from '../error' ;
28
27
import { CancellationToken , TypedEventEmitter } from '../mongo_types' ;
29
28
import type { Server } from '../sdam/server' ;
30
- import { type Callback , eachAsync , List , makeCounter , TimeoutController } from '../utils' ;
29
+ import {
30
+ type Callback ,
31
+ eachAsync ,
32
+ List ,
33
+ makeCounter ,
34
+ promiseWithResolvers ,
35
+ TimeoutController
36
+ } from '../utils' ;
31
37
import { connect } from './connect' ;
32
38
import { Connection , type ConnectionEvents , type ConnectionOptions } from './connection' ;
33
39
import {
@@ -100,7 +106,8 @@ export interface ConnectionPoolOptions extends Omit<ConnectionOptions, 'id' | 'g
100
106
101
107
/** @internal */
102
108
export interface WaitQueueMember {
103
- callback : Callback < Connection > ;
109
+ resolve : ( conn : Connection ) => void ;
110
+ reject : ( err : AnyError ) => void ;
104
111
timeoutController : TimeoutController ;
105
112
[ kCancelled ] ?: boolean ;
106
113
}
@@ -350,16 +357,18 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
350
357
* will be held by the pool. This means that if a connection is checked out it MUST be checked back in or
351
358
* explicitly destroyed by the new owner.
352
359
*/
353
- checkOut ( callback : Callback < Connection > ) : void {
360
+ async checkOut ( ) : Promise < Connection > {
354
361
this . emitAndLog (
355
362
ConnectionPool . CONNECTION_CHECK_OUT_STARTED ,
356
363
new ConnectionCheckOutStartedEvent ( this )
357
364
) ;
358
365
359
366
const waitQueueTimeoutMS = this . options . waitQueueTimeoutMS ;
360
367
368
+ const { promise, resolve, reject } = promiseWithResolvers < Connection > ( ) ;
361
369
const waitQueueMember : WaitQueueMember = {
362
- callback,
370
+ resolve,
371
+ reject,
363
372
timeoutController : new TimeoutController ( waitQueueTimeoutMS )
364
373
} ;
365
374
waitQueueMember . timeoutController . signal . addEventListener ( 'abort' , ( ) => {
@@ -370,7 +379,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
370
379
ConnectionPool . CONNECTION_CHECK_OUT_FAILED ,
371
380
new ConnectionCheckOutFailedEvent ( this , 'timeout' )
372
381
) ;
373
- waitQueueMember . callback (
382
+ waitQueueMember . reject (
374
383
new WaitQueueTimeoutError (
375
384
this . loadBalanced
376
385
? this . waitQueueErrorMetrics ( )
@@ -382,6 +391,8 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
382
391
383
392
this [ kWaitQueue ] . push ( waitQueueMember ) ;
384
393
process . nextTick ( ( ) => this . processWaitQueue ( ) ) ;
394
+
395
+ return promise ;
385
396
}
386
397
387
398
/**
@@ -534,115 +545,35 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
534
545
}
535
546
536
547
/**
537
- * Runs a lambda with an implicitly checked out connection, checking that connection back in when the lambda
538
- * has completed by calling back.
539
- *
540
- * NOTE: please note the required signature of `fn`
541
- *
542
- * @remarks When in load balancer mode, connections can be pinned to cursors or transactions.
543
- * In these cases we pass the connection in to this method to ensure it is used and a new
544
- * connection is not checked out.
545
- *
546
- * @param conn - A pinned connection for use in load balancing mode.
547
- * @param fn - A function which operates on a managed connection
548
- * @param callback - The original callback
549
- */
550
- withConnection (
551
- conn : Connection | undefined ,
552
- fn : WithConnectionCallback ,
553
- callback : Callback < Connection >
554
- ) : void {
555
- if ( conn ) {
556
- // use the provided connection, and do _not_ check it in after execution
557
- fn ( undefined , conn , ( fnErr , result ) => {
558
- if ( fnErr ) {
559
- return this . withReauthentication ( fnErr , conn , fn , callback ) ;
560
- }
561
- callback ( undefined , result ) ;
562
- } ) ;
563
- return ;
564
- }
565
-
566
- this . checkOut ( ( err , conn ) => {
567
- // don't callback with `err` here, we might want to act upon it inside `fn`
568
- fn ( err as MongoError , conn , ( fnErr , result ) => {
569
- if ( fnErr ) {
570
- if ( conn ) {
571
- this . withReauthentication ( fnErr , conn , fn , callback ) ;
572
- } else {
573
- callback ( fnErr ) ;
574
- }
575
- } else {
576
- callback ( undefined , result ) ;
577
- }
578
-
579
- if ( conn ) {
580
- this . checkIn ( conn ) ;
581
- }
582
- } ) ;
583
- } ) ;
584
- }
585
-
586
- private withReauthentication (
587
- fnErr : AnyError ,
588
- conn : Connection ,
589
- fn : WithConnectionCallback ,
590
- callback : Callback < Connection >
591
- ) {
592
- if ( fnErr instanceof MongoError && fnErr . code === MONGODB_ERROR_CODES . Reauthenticate ) {
593
- this . reauthenticate ( conn , fn , ( error , res ) => {
594
- if ( error ) {
595
- return callback ( error ) ;
596
- }
597
- callback ( undefined , res ) ;
598
- } ) ;
599
- } else {
600
- callback ( fnErr ) ;
601
- }
602
- }
603
-
604
- /**
605
- * Reauthenticate on the same connection and then retry the operation.
548
+ * @internal
549
+ * Reauthenticate a connection
606
550
*/
607
- private reauthenticate (
608
- connection : Connection ,
609
- fn : WithConnectionCallback ,
610
- callback : Callback
611
- ) : void {
551
+ async reauthenticate ( connection : Connection ) : Promise < void > {
612
552
const authContext = connection . authContext ;
613
553
if ( ! authContext ) {
614
- return callback ( new MongoRuntimeError ( 'No auth context found on connection.' ) ) ;
554
+ throw new MongoRuntimeError ( 'No auth context found on connection.' ) ;
615
555
}
616
556
const credentials = authContext . credentials ;
617
557
if ( ! credentials ) {
618
- return callback (
619
- new MongoMissingCredentialsError (
620
- 'Connection is missing credentials when asked to reauthenticate'
621
- )
558
+ throw new MongoMissingCredentialsError (
559
+ 'Connection is missing credentials when asked to reauthenticate'
622
560
) ;
623
561
}
562
+
624
563
const resolvedCredentials = credentials . resolveAuthMechanism ( connection . hello ) ;
625
564
const provider = this [ kServer ] . topology . client . s . authProviders . getOrCreateProvider (
626
565
resolvedCredentials . mechanism
627
566
) ;
567
+
628
568
if ( ! provider ) {
629
- return callback (
630
- new MongoMissingCredentialsError (
631
- `Reauthenticate failed due to no auth provider for ${ credentials . mechanism } `
632
- )
569
+ throw new MongoMissingCredentialsError (
570
+ `Reauthenticate failed due to no auth provider for ${ credentials . mechanism } `
633
571
) ;
634
572
}
635
- provider . reauth ( authContext ) . then (
636
- ( ) => {
637
- fn ( undefined , connection , ( fnErr , fnResult ) => {
638
- if ( fnErr ) {
639
- return callback ( fnErr ) ;
640
- }
641
- callback ( undefined , fnResult ) ;
642
- } ) ;
643
- } ,
644
- error => callback ( error )
645
- ) ;
573
+
574
+ await provider . reauth ( authContext ) ;
575
+
576
+ return ;
646
577
}
647
578
648
579
/** Clear the min pool size timer */
@@ -841,7 +772,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
841
772
) ;
842
773
waitQueueMember . timeoutController . clear ( ) ;
843
774
this [ kWaitQueue ] . shift ( ) ;
844
- waitQueueMember . callback ( error ) ;
775
+ waitQueueMember . reject ( error ) ;
845
776
continue ;
846
777
}
847
778
@@ -863,7 +794,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
863
794
waitQueueMember . timeoutController . clear ( ) ;
864
795
865
796
this [ kWaitQueue ] . shift ( ) ;
866
- waitQueueMember . callback ( undefined , connection ) ;
797
+ waitQueueMember . resolve ( connection ) ;
867
798
}
868
799
}
869
800
@@ -889,16 +820,17 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
889
820
// TODO(NODE-5192): Remove this cast
890
821
new ConnectionCheckOutFailedEvent ( this , 'connectionError' , err as MongoError )
891
822
) ;
823
+ waitQueueMember . reject ( err ) ;
892
824
} else if ( connection ) {
893
825
this [ kCheckedOut ] . add ( connection ) ;
894
826
this . emitAndLog (
895
827
ConnectionPool . CONNECTION_CHECKED_OUT ,
896
828
new ConnectionCheckedOutEvent ( this , connection )
897
829
) ;
830
+ waitQueueMember . resolve ( connection ) ;
898
831
}
899
832
900
833
waitQueueMember . timeoutController . clear ( ) ;
901
- waitQueueMember . callback ( err , connection ) ;
902
834
}
903
835
process . nextTick ( ( ) => this . processWaitQueue ( ) ) ;
904
836
} ) ;
0 commit comments