@@ -136,7 +136,12 @@ interface UnderlyingCall {
136
136
* sent
137
137
* NO_RETRY: Retries are disabled. Exists to track the transition to COMMITTED
138
138
*/
139
- type RetryingCallState = 'RETRY' | 'HEDGING' | 'TRANSPARENT_ONLY' | 'COMMITTED' | 'NO_RETRY' ;
139
+ type RetryingCallState =
140
+ | 'RETRY'
141
+ | 'HEDGING'
142
+ | 'TRANSPARENT_ONLY'
143
+ | 'COMMITTED'
144
+ | 'NO_RETRY' ;
140
145
141
146
/**
142
147
* The different types of objects that can be stored in the write buffer, with
@@ -217,7 +222,9 @@ export class RetryingCall implements Call, DeadlineInfoProvider {
217
222
private readonly bufferTracker : MessageBufferTracker ,
218
223
private readonly retryThrottler ?: RetryThrottler
219
224
) {
220
- const maxAttemptsLimit = channel . getOptions ( ) [ 'grpc-node.retry_max_attempts_limit' ] ?? DEFAULT_MAX_ATTEMPTS_LIMIT ;
225
+ const maxAttemptsLimit =
226
+ channel . getOptions ( ) [ 'grpc-node.retry_max_attempts_limit' ] ??
227
+ DEFAULT_MAX_ATTEMPTS_LIMIT ;
221
228
if ( callConfig . methodConfig . retryPolicy ) {
222
229
this . state = 'RETRY' ;
223
230
const retryPolicy = callConfig . methodConfig . retryPolicy ;
@@ -230,7 +237,10 @@ export class RetryingCall implements Call, DeadlineInfoProvider {
230
237
this . maxAttempts = Math . min ( retryPolicy . maxAttempts , maxAttemptsLimit ) ;
231
238
} else if ( callConfig . methodConfig . hedgingPolicy ) {
232
239
this . state = 'HEDGING' ;
233
- this . maxAttempts = Math . min ( callConfig . methodConfig . hedgingPolicy . maxAttempts , maxAttemptsLimit ) ;
240
+ this . maxAttempts = Math . min (
241
+ callConfig . methodConfig . hedgingPolicy . maxAttempts ,
242
+ maxAttemptsLimit
243
+ ) ;
234
244
} else if ( channel . getOptions ( ) [ 'grpc.enable_retries' ] === 0 ) {
235
245
this . state = 'NO_RETRY' ;
236
246
this . maxAttempts = 1 ;
@@ -247,10 +257,17 @@ export class RetryingCall implements Call, DeadlineInfoProvider {
247
257
const deadlineInfo : string [ ] = [ ] ;
248
258
const latestCall = this . underlyingCalls [ this . underlyingCalls . length - 1 ] ;
249
259
if ( this . underlyingCalls . length > 1 ) {
250
- deadlineInfo . push ( `previous attempts: ${ this . underlyingCalls . length - 1 } ` ) ;
260
+ deadlineInfo . push (
261
+ `previous attempts: ${ this . underlyingCalls . length - 1 } `
262
+ ) ;
251
263
}
252
264
if ( latestCall . startTime > this . startTime ) {
253
- deadlineInfo . push ( `time to current attempt start: ${ formatDateDifference ( this . startTime , latestCall . startTime ) } ` ) ;
265
+ deadlineInfo . push (
266
+ `time to current attempt start: ${ formatDateDifference (
267
+ this . startTime ,
268
+ latestCall . startTime
269
+ ) } `
270
+ ) ;
254
271
}
255
272
deadlineInfo . push ( ...latestCall . call . getDeadlineInfo ( ) ) ;
256
273
return deadlineInfo ;
@@ -412,12 +429,18 @@ export class RetryingCall implements Call, DeadlineInfoProvider {
412
429
) ;
413
430
}
414
431
432
+ private getNextRetryJitter ( ) {
433
+ /* Jitter of +-20% is applied: https://github.com/grpc/proposal/blob/master/A6-client-retries.md#exponential-backoff */
434
+ return Math . random ( ) * ( 1.2 - 0.8 ) + 0.8 ;
435
+ }
436
+
415
437
private getNextRetryBackoffMs ( ) {
416
438
const retryPolicy = this . callConfig ?. methodConfig . retryPolicy ;
417
439
if ( ! retryPolicy ) {
418
440
return 0 ;
419
441
}
420
- const nextBackoffMs = Math . random ( ) * this . nextRetryBackoffSec * 1000 ;
442
+ const jitter = this . getNextRetryJitter ( ) ;
443
+ const nextBackoffMs = jitter * this . nextRetryBackoffSec * 1000 ;
421
444
const maxBackoffSec = Number (
422
445
retryPolicy . maxBackoff . substring ( 0 , retryPolicy . maxBackoff . length - 1 )
423
446
) ;
@@ -669,7 +692,7 @@ export class RetryingCall implements Call, DeadlineInfoProvider {
669
692
state : 'ACTIVE' ,
670
693
call : child ,
671
694
nextMessageToSend : 0 ,
672
- startTime : new Date ( )
695
+ startTime : new Date ( ) ,
673
696
} ) ;
674
697
const previousAttempts = this . attempts - 1 ;
675
698
const initialMetadata = this . initialMetadata ! . clone ( ) ;
@@ -862,7 +885,9 @@ export class RetryingCall implements Call, DeadlineInfoProvider {
862
885
}
863
886
getAuthContext ( ) : AuthContext | null {
864
887
if ( this . committedCallIndex !== null ) {
865
- return this . underlyingCalls [ this . committedCallIndex ] . call . getAuthContext ( ) ;
888
+ return this . underlyingCalls [
889
+ this . committedCallIndex
890
+ ] . call . getAuthContext ( ) ;
866
891
} else {
867
892
return null ;
868
893
}
0 commit comments