@@ -20,7 +20,10 @@ import {
20
20
isSystemError ,
21
21
} from "./error" ;
22
22
import { base64Encode } from "./lib/btoa" ;
23
- import { ERROR_ARANGO_CONFLICT } from "./lib/codes" ;
23
+ import {
24
+ ERROR_ARANGO_CONFLICT ,
25
+ ERROR_ARANGO_MAINTENANCE_MODE ,
26
+ } from "./lib/codes" ;
24
27
import { Errback } from "./lib/errback" ;
25
28
import { normalizeUrl } from "./lib/normalizeUrl" ;
26
29
import { querystringify } from "./lib/querystringify" ;
@@ -283,8 +286,9 @@ type Task = {
283
286
stack ?: ( ) => string ;
284
287
allowDirtyRead : boolean ;
285
288
retryOnConflict : number ;
286
- resolve : ( res : ArangojsResponse ) => void ;
289
+ resolve : ( result : any ) => void ;
287
290
reject : ( error : Error ) => void ;
291
+ transform ?: ( res : ArangojsResponse ) => any ;
288
292
retries : number ;
289
293
options : {
290
294
method : string ;
@@ -495,9 +499,7 @@ export class Connection {
495
499
protected _arangoVersion : number = 30900 ;
496
500
protected _headers : Headers ;
497
501
protected _loadBalancingStrategy : LoadBalancingStrategy ;
498
- protected _useFailOver : boolean ;
499
- protected _shouldRetry : boolean ;
500
- protected _maxRetries : number ;
502
+ protected _maxRetries : number | false ;
501
503
protected _maxTasks : number ;
502
504
protected _queue = new LinkedList < Task > ( ) ;
503
505
protected _databases = new Map < string , Database > ( ) ;
@@ -507,8 +509,8 @@ export class Connection {
507
509
protected _activeDirtyHost : number ;
508
510
protected _transactionId : string | null = null ;
509
511
protected _precaptureStackTraces : boolean ;
510
- protected _responseQueueTimeSamples : number ;
511
512
protected _queueTimes = new LinkedList < [ number , number ] > ( ) ;
513
+ protected _responseQueueTimeSamples : number ;
512
514
513
515
/**
514
516
* @internal
@@ -543,18 +545,15 @@ export class Connection {
543
545
this . _maxTasks = this . _agentOptions . maxSockets ;
544
546
this . _headers = { ...config . headers } ;
545
547
this . _loadBalancingStrategy = config . loadBalancingStrategy ?? "NONE" ;
546
- this . _useFailOver = this . _loadBalancingStrategy !== "ROUND_ROBIN" ;
547
548
this . _precaptureStackTraces = Boolean ( config . precaptureStackTraces ) ;
548
549
this . _responseQueueTimeSamples = config . responseQueueTimeSamples ?? 10 ;
549
550
if ( this . _responseQueueTimeSamples < 0 ) {
550
551
this . _responseQueueTimeSamples = Infinity ;
551
552
}
552
553
if ( config . maxRetries === false ) {
553
- this . _shouldRetry = false ;
554
- this . _maxRetries = 0 ;
554
+ this . _maxRetries = false ;
555
555
} else {
556
- this . _shouldRetry = true ;
557
- this . _maxRetries = config . maxRetries ?? 0 ;
556
+ this . _maxRetries = Number ( config . maxRetries ?? 0 ) ;
558
557
}
559
558
560
559
this . addToHostList ( URLS ) ;
@@ -615,12 +614,66 @@ export class Connection {
615
614
this . _activeTasks += 1 ;
616
615
const callback : Errback < ArangojsResponse > = ( err , res ) => {
617
616
this . _activeTasks -= 1 ;
617
+ if ( ! err && res ) {
618
+ if ( res . statusCode === 503 && res . headers [ LEADER_ENDPOINT_HEADER ] ) {
619
+ const url = res . headers [ LEADER_ENDPOINT_HEADER ] ! ;
620
+ const [ index ] = this . addToHostList ( url ) ;
621
+ task . host = index ;
622
+ if ( this . _activeHost === host ) {
623
+ this . _activeHost = index ;
624
+ }
625
+ this . _queue . push ( task ) ;
626
+ } else {
627
+ res . arangojsHostId = host ;
628
+ const contentType = res . headers [ "content-type" ] ;
629
+ const queueTime = res . headers [ "x-arango-queue-time-seconds" ] ;
630
+ if ( queueTime ) {
631
+ this . _queueTimes . push ( [ Date . now ( ) , Number ( queueTime ) ] ) ;
632
+ while ( this . _responseQueueTimeSamples < this . _queueTimes . length ) {
633
+ this . _queueTimes . shift ( ) ;
634
+ }
635
+ }
636
+ let parsedBody : any = undefined ;
637
+ if ( res . body . length && contentType && contentType . match ( MIME_JSON ) ) {
638
+ try {
639
+ parsedBody = res . body ;
640
+ parsedBody = JSON . parse ( parsedBody ) ;
641
+ } catch ( e : any ) {
642
+ if ( ! task . options . expectBinary ) {
643
+ if ( typeof parsedBody !== "string" ) {
644
+ parsedBody = res . body . toString ( "utf-8" ) ;
645
+ }
646
+ e . res = res ;
647
+ if ( task . stack ) {
648
+ e . stack += task . stack ( ) ;
649
+ }
650
+ callback ( e ) ;
651
+ return ;
652
+ }
653
+ }
654
+ } else if ( res . body && ! task . options . expectBinary ) {
655
+ parsedBody = res . body . toString ( "utf-8" ) ;
656
+ } else {
657
+ parsedBody = res . body ;
658
+ }
659
+ if ( isArangoErrorResponse ( parsedBody ) ) {
660
+ res . body = parsedBody ;
661
+ err = new ArangoError ( res ) ;
662
+ } else if ( res . statusCode && res . statusCode >= 400 ) {
663
+ res . body = parsedBody ;
664
+ err = new HttpError ( res ) ;
665
+ } else {
666
+ if ( ! task . options . expectBinary ) res . body = parsedBody ;
667
+ task . resolve ( task . transform ? task . transform ( res ) : ( res as any ) ) ;
668
+ }
669
+ }
670
+ }
618
671
if ( err ) {
619
672
if (
620
673
! task . allowDirtyRead &&
621
674
this . _hosts . length > 1 &&
622
675
this . _activeHost === host &&
623
- this . _useFailOver
676
+ this . _loadBalancingStrategy !== "ROUND_ROBIN"
624
677
) {
625
678
this . _activeHost = ( this . _activeHost + 1 ) % this . _hosts . length ;
626
679
}
@@ -632,12 +685,14 @@ export class Connection {
632
685
task . retryOnConflict -= 1 ;
633
686
this . _queue . push ( task ) ;
634
687
} else if (
635
- ! task . host &&
636
- this . _shouldRetry &&
637
- task . retries < ( this . _maxRetries || this . _hosts . length - 1 ) &&
638
- isSystemError ( err ) &&
639
- err . syscall === "connect" &&
640
- err . code === "ECONNREFUSED"
688
+ ( ( isSystemError ( err ) &&
689
+ err . syscall === "connect" &&
690
+ err . code === "ECONNREFUSED" ) ||
691
+ ( isArangoError ( err ) &&
692
+ err . errorNum === ERROR_ARANGO_MAINTENANCE_MODE ) ) &&
693
+ task . host === undefined &&
694
+ this . _maxRetries !== false &&
695
+ task . retries < ( this . _maxRetries || this . _hosts . length - 1 )
641
696
) {
642
697
task . retries += 1 ;
643
698
this . _queue . push ( task ) ;
@@ -647,23 +702,6 @@ export class Connection {
647
702
}
648
703
task . reject ( err ) ;
649
704
}
650
- } else {
651
- const response = res ! ;
652
- if (
653
- response . statusCode === 503 &&
654
- response . headers [ LEADER_ENDPOINT_HEADER ]
655
- ) {
656
- const url = response . headers [ LEADER_ENDPOINT_HEADER ] ! ;
657
- const [ index ] = this . addToHostList ( url ) ;
658
- task . host = index ;
659
- if ( this . _activeHost === host ) {
660
- this . _activeHost = index ;
661
- }
662
- this . _queue . push ( task ) ;
663
- } else {
664
- response . arangojsHostId = host ;
665
- task . resolve ( response ) ;
666
- }
667
705
}
668
706
this . _runQueue ( ) ;
669
707
} ;
@@ -922,57 +960,8 @@ export class Connection {
922
960
body,
923
961
} ,
924
962
reject,
925
- resolve : ( res : ArangojsResponse ) => {
926
- const contentType = res . headers [ "content-type" ] ;
927
- const queueTime = res . headers [ "x-arango-queue-time-seconds" ] ;
928
- if ( queueTime ) {
929
- this . _queueTimes . push ( [ Date . now ( ) , Number ( queueTime ) ] ) ;
930
- while ( this . _responseQueueTimeSamples < this . _queueTimes . length ) {
931
- this . _queueTimes . shift ( ) ;
932
- }
933
- }
934
- let parsedBody : any = undefined ;
935
- if ( res . body . length && contentType && contentType . match ( MIME_JSON ) ) {
936
- try {
937
- parsedBody = res . body ;
938
- parsedBody = JSON . parse ( parsedBody ) ;
939
- } catch ( e : any ) {
940
- if ( ! expectBinary ) {
941
- if ( typeof parsedBody !== "string" ) {
942
- parsedBody = res . body . toString ( "utf-8" ) ;
943
- }
944
- e . response = res ;
945
- if ( task . stack ) {
946
- e . stack += task . stack ( ) ;
947
- }
948
- reject ( e ) ;
949
- return ;
950
- }
951
- }
952
- } else if ( res . body && ! expectBinary ) {
953
- parsedBody = res . body . toString ( "utf-8" ) ;
954
- } else {
955
- parsedBody = res . body ;
956
- }
957
- if ( isArangoErrorResponse ( parsedBody ) ) {
958
- res . body = parsedBody ;
959
- const err = new ArangoError ( res ) ;
960
- if ( task . stack ) {
961
- err . stack += task . stack ( ) ;
962
- }
963
- reject ( err ) ;
964
- } else if ( res . statusCode && res . statusCode >= 400 ) {
965
- res . body = parsedBody ;
966
- const err = new HttpError ( res ) ;
967
- if ( task . stack ) {
968
- err . stack += task . stack ( ) ;
969
- }
970
- reject ( err ) ;
971
- } else {
972
- if ( ! expectBinary ) res . body = parsedBody ;
973
- resolve ( transform ? transform ( res ) : ( res as any ) ) ;
974
- }
975
- } ,
963
+ resolve,
964
+ transform,
976
965
} ;
977
966
978
967
if ( this . _precaptureStackTraces ) {
0 commit comments