@@ -136,7 +136,12 @@ interface UnderlyingCall {
136136 * sent
137137 * NO_RETRY: Retries are disabled. Exists to track the transition to COMMITTED
138138 */
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' ;
140145
141146/**
142147 * The different types of objects that can be stored in the write buffer, with
@@ -217,7 +222,9 @@ export class RetryingCall implements Call, DeadlineInfoProvider {
217222 private readonly bufferTracker : MessageBufferTracker ,
218223 private readonly retryThrottler ?: RetryThrottler
219224 ) {
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 ;
221228 if ( callConfig . methodConfig . retryPolicy ) {
222229 this . state = 'RETRY' ;
223230 const retryPolicy = callConfig . methodConfig . retryPolicy ;
@@ -230,7 +237,10 @@ export class RetryingCall implements Call, DeadlineInfoProvider {
230237 this . maxAttempts = Math . min ( retryPolicy . maxAttempts , maxAttemptsLimit ) ;
231238 } else if ( callConfig . methodConfig . hedgingPolicy ) {
232239 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+ ) ;
234244 } else if ( channel . getOptions ( ) [ 'grpc.enable_retries' ] === 0 ) {
235245 this . state = 'NO_RETRY' ;
236246 this . maxAttempts = 1 ;
@@ -247,10 +257,17 @@ export class RetryingCall implements Call, DeadlineInfoProvider {
247257 const deadlineInfo : string [ ] = [ ] ;
248258 const latestCall = this . underlyingCalls [ this . underlyingCalls . length - 1 ] ;
249259 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+ ) ;
251263 }
252264 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+ ) ;
254271 }
255272 deadlineInfo . push ( ...latestCall . call . getDeadlineInfo ( ) ) ;
256273 return deadlineInfo ;
@@ -412,12 +429,18 @@ export class RetryingCall implements Call, DeadlineInfoProvider {
412429 ) ;
413430 }
414431
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+
415437 private getNextRetryBackoffMs ( ) {
416438 const retryPolicy = this . callConfig ?. methodConfig . retryPolicy ;
417439 if ( ! retryPolicy ) {
418440 return 0 ;
419441 }
420- const nextBackoffMs = Math . random ( ) * this . nextRetryBackoffSec * 1000 ;
442+ const jitter = this . getNextRetryJitter ( ) ;
443+ const nextBackoffMs = jitter * this . nextRetryBackoffSec * 1000 ;
421444 const maxBackoffSec = Number (
422445 retryPolicy . maxBackoff . substring ( 0 , retryPolicy . maxBackoff . length - 1 )
423446 ) ;
@@ -669,7 +692,7 @@ export class RetryingCall implements Call, DeadlineInfoProvider {
669692 state : 'ACTIVE' ,
670693 call : child ,
671694 nextMessageToSend : 0 ,
672- startTime : new Date ( )
695+ startTime : new Date ( ) ,
673696 } ) ;
674697 const previousAttempts = this . attempts - 1 ;
675698 const initialMetadata = this . initialMetadata ! . clone ( ) ;
@@ -862,7 +885,9 @@ export class RetryingCall implements Call, DeadlineInfoProvider {
862885 }
863886 getAuthContext ( ) : AuthContext | null {
864887 if ( this . committedCallIndex !== null ) {
865- return this . underlyingCalls [ this . committedCallIndex ] . call . getAuthContext ( ) ;
888+ return this . underlyingCalls [
889+ this . committedCallIndex
890+ ] . call . getAuthContext ( ) ;
866891 } else {
867892 return null ;
868893 }
0 commit comments