@@ -147,6 +147,17 @@ public double nextDouble() {
147147 private final ChannelBufferMeter channelBufferUsed = new ChannelBufferMeter ();
148148 private final FakeClock fakeClock = new FakeClock ();
149149
150+ private static long calculateBackoffWithRetries (int retryCount ) {
151+ // Calculate the exponential backoff delay with jitter
152+ double exponent = retryCount > 0 ? Math .pow (BACKOFF_MULTIPLIER , retryCount ) : 1 ;
153+ long delay = (long ) (INITIAL_BACKOFF_IN_SECONDS * exponent );
154+ return RetriableStream .intervalWithJitter (delay );
155+ }
156+
157+ private static long calculateMaxBackoff () {
158+ return RetriableStream .intervalWithJitter (MAX_BACKOFF_IN_SECONDS );
159+ }
160+
150161 private final class RecordedRetriableStream extends RetriableStream <String > {
151162 RecordedRetriableStream (MethodDescriptor <String , ?> method , Metadata headers ,
152163 ChannelBufferMeter channelBufferUsed , long perRpcBufferLimit , long channelBufferLimit ,
@@ -307,7 +318,7 @@ public Void answer(InvocationOnMock in) {
307318 retriableStream .sendMessage ("msg1 during backoff1" );
308319 retriableStream .sendMessage ("msg2 during backoff1" );
309320
310- fakeClock .forwardTime (( long ) ( INITIAL_BACKOFF_IN_SECONDS * FAKE_RANDOM ) - 1L , TimeUnit .SECONDS );
321+ fakeClock .forwardTime (calculateBackoffWithRetries ( 0 ) - 1L , TimeUnit .SECONDS );
311322 inOrder .verifyNoMoreInteractions ();
312323 assertEquals (1 , fakeClock .numPendingTasks ());
313324 fakeClock .forwardTime (1L , TimeUnit .SECONDS );
@@ -364,9 +375,7 @@ public Void answer(InvocationOnMock in) {
364375 retriableStream .sendMessage ("msg2 during backoff2" );
365376 retriableStream .sendMessage ("msg3 during backoff2" );
366377
367- fakeClock .forwardTime (
368- (long ) (INITIAL_BACKOFF_IN_SECONDS * BACKOFF_MULTIPLIER * FAKE_RANDOM ) - 1L ,
369- TimeUnit .SECONDS );
378+ fakeClock .forwardTime (calculateBackoffWithRetries (1 ) - 1L , TimeUnit .SECONDS );
370379 inOrder .verifyNoMoreInteractions ();
371380 assertEquals (1 , fakeClock .numPendingTasks ());
372381 fakeClock .forwardTime (1L , TimeUnit .SECONDS );
@@ -459,7 +468,7 @@ public void retry_headersRead_cancel() {
459468 sublistenerCaptor1 .getValue ().closed (
460469 Status .fromCode (RETRIABLE_STATUS_CODE_1 ), PROCESSED , new Metadata ());
461470 assertEquals (1 , fakeClock .numPendingTasks ());
462- fakeClock .forwardTime (( long ) ( INITIAL_BACKOFF_IN_SECONDS * FAKE_RANDOM ), TimeUnit .SECONDS );
471+ fakeClock .forwardTime (calculateBackoffWithRetries ( 0 ), TimeUnit .SECONDS );
463472
464473 ArgumentCaptor <ClientStreamListener > sublistenerCaptor2 =
465474 ArgumentCaptor .forClass (ClientStreamListener .class );
@@ -518,7 +527,7 @@ public void retry_headersRead_closed() {
518527 doReturn (mockStream2 ).when (retriableStreamRecorder ).newSubstream (1 );
519528 sublistenerCaptor1 .getValue ().closed (
520529 Status .fromCode (RETRIABLE_STATUS_CODE_1 ), PROCESSED , new Metadata ());
521- fakeClock .forwardTime (( long ) ( INITIAL_BACKOFF_IN_SECONDS * FAKE_RANDOM ), TimeUnit .SECONDS );
530+ fakeClock .forwardTime (calculateBackoffWithRetries ( 0 ), TimeUnit .SECONDS );
522531
523532 ArgumentCaptor <ClientStreamListener > sublistenerCaptor2 =
524533 ArgumentCaptor .forClass (ClientStreamListener .class );
@@ -584,7 +593,7 @@ public void retry_cancel_closed() {
584593 doReturn (mockStream2 ).when (retriableStreamRecorder ).newSubstream (1 );
585594 sublistenerCaptor1 .getValue ().closed (
586595 Status .fromCode (RETRIABLE_STATUS_CODE_1 ), PROCESSED , new Metadata ());
587- fakeClock .forwardTime (( long ) ( INITIAL_BACKOFF_IN_SECONDS * FAKE_RANDOM ), TimeUnit .SECONDS );
596+ fakeClock .forwardTime (calculateBackoffWithRetries ( 0 ), TimeUnit .SECONDS );
588597
589598 ArgumentCaptor <ClientStreamListener > sublistenerCaptor2 =
590599 ArgumentCaptor .forClass (ClientStreamListener .class );
@@ -687,7 +696,7 @@ public void retry_unretriableClosed_cancel() {
687696 doReturn (mockStream2 ).when (retriableStreamRecorder ).newSubstream (1 );
688697 sublistenerCaptor1 .getValue ().closed (
689698 Status .fromCode (RETRIABLE_STATUS_CODE_1 ), PROCESSED , new Metadata ());
690- fakeClock .forwardTime (( long ) ( INITIAL_BACKOFF_IN_SECONDS * FAKE_RANDOM ), TimeUnit .SECONDS );
699+ fakeClock .forwardTime (calculateBackoffWithRetries ( 0 ), TimeUnit .SECONDS );
691700
692701 ArgumentCaptor <ClientStreamListener > sublistenerCaptor2 =
693702 ArgumentCaptor .forClass (ClientStreamListener .class );
@@ -821,7 +830,7 @@ public boolean isReady() {
821830 // send more requests during backoff
822831 retriableStream .request (789 );
823832
824- fakeClock .forwardTime (( long ) ( INITIAL_BACKOFF_IN_SECONDS * FAKE_RANDOM ), TimeUnit .SECONDS );
833+ fakeClock .forwardTime (calculateBackoffWithRetries ( 0 ), TimeUnit .SECONDS );
825834
826835 inOrder .verify (mockStream2 ).start (sublistenerCaptor2 .get ());
827836 inOrder .verify (mockStream2 ).request (3 );
@@ -875,7 +884,7 @@ public void request(int numMessages) {
875884 doReturn (mockStream2 ).when (retriableStreamRecorder ).newSubstream (1 );
876885 sublistenerCaptor1 .getValue ().closed (
877886 Status .fromCode (RETRIABLE_STATUS_CODE_1 ), PROCESSED , new Metadata ());
878- fakeClock .forwardTime (( long ) ( INITIAL_BACKOFF_IN_SECONDS * FAKE_RANDOM ), TimeUnit .SECONDS );
887+ fakeClock .forwardTime (calculateBackoffWithRetries ( 0 ), TimeUnit .SECONDS );
879888
880889 inOrder .verify (mockStream2 ).start (sublistenerCaptor2 .capture ());
881890 inOrder .verify (mockStream2 ).request (3 );
@@ -920,7 +929,7 @@ public void start(ClientStreamListener listener) {
920929 doReturn (mockStream2 ).when (retriableStreamRecorder ).newSubstream (1 );
921930 sublistenerCaptor1 .getValue ().closed (
922931 Status .fromCode (RETRIABLE_STATUS_CODE_1 ), PROCESSED , new Metadata ());
923- fakeClock .forwardTime (( long ) ( INITIAL_BACKOFF_IN_SECONDS * FAKE_RANDOM ), TimeUnit .SECONDS );
932+ fakeClock .forwardTime (calculateBackoffWithRetries ( 0 ), TimeUnit .SECONDS );
924933
925934 inOrder .verify (mockStream2 ).start (sublistenerCaptor2 .capture ());
926935 inOrder .verify (retriableStreamRecorder ).postCommit ();
@@ -1028,7 +1037,7 @@ public boolean isReady() {
10281037 retriableStream .request (789 );
10291038 readiness .add (retriableStream .isReady ()); // expected false b/c in backoff
10301039
1031- fakeClock .forwardTime (( long ) ( INITIAL_BACKOFF_IN_SECONDS * FAKE_RANDOM ), TimeUnit .SECONDS );
1040+ fakeClock .forwardTime (calculateBackoffWithRetries ( 0 ), TimeUnit .SECONDS );
10321041
10331042 verify (mockStream2 ).start (any (ClientStreamListener .class ));
10341043 readiness .add (retriableStream .isReady ()); // expected true
@@ -1110,7 +1119,7 @@ public void addPrevRetryAttemptsToRespHeaders() {
11101119 doReturn (mockStream2 ).when (retriableStreamRecorder ).newSubstream (1 );
11111120 sublistenerCaptor1 .getValue ().closed (
11121121 Status .fromCode (RETRIABLE_STATUS_CODE_1 ), PROCESSED , new Metadata ());
1113- fakeClock .forwardTime (( long ) ( INITIAL_BACKOFF_IN_SECONDS * FAKE_RANDOM ), TimeUnit .SECONDS );
1122+ fakeClock .forwardTime (calculateBackoffWithRetries ( 0 ), TimeUnit .SECONDS );
11141123
11151124 ArgumentCaptor <ClientStreamListener > sublistenerCaptor2 =
11161125 ArgumentCaptor .forClass (ClientStreamListener .class );
@@ -1160,13 +1169,12 @@ public void start(ClientStreamListener listener) {
11601169 listener1 .closed (
11611170 Status .fromCode (RETRIABLE_STATUS_CODE_1 ), PROCESSED , new Metadata ());
11621171 assertEquals (1 , fakeClock .numPendingTasks ());
1163- fakeClock .forwardTime (( long ) ( INITIAL_BACKOFF_IN_SECONDS * FAKE_RANDOM ), TimeUnit .SECONDS );
1172+ fakeClock .forwardTime (calculateBackoffWithRetries ( 0 ), TimeUnit .SECONDS );
11641173 assertEquals (1 , fakeClock .numPendingTasks ());
11651174
11661175 // send requests during backoff
11671176 retriableStream .request (3 );
1168- fakeClock .forwardTime (
1169- (long ) (INITIAL_BACKOFF_IN_SECONDS * BACKOFF_MULTIPLIER * FAKE_RANDOM ), TimeUnit .SECONDS );
1177+ fakeClock .forwardTime (calculateBackoffWithRetries (1 ), TimeUnit .SECONDS );
11701178
11711179 retriableStream .request (1 );
11721180 verify (mockStream1 , never ()).request (anyInt ());
@@ -1207,7 +1215,7 @@ public void start(ClientStreamListener listener) {
12071215 // retry
12081216 listener1 .closed (
12091217 Status .fromCode (RETRIABLE_STATUS_CODE_1 ), PROCESSED , new Metadata ());
1210- fakeClock .forwardTime (( long ) ( INITIAL_BACKOFF_IN_SECONDS * FAKE_RANDOM ), TimeUnit .SECONDS );
1218+ fakeClock .forwardTime (calculateBackoffWithRetries ( 0 ), TimeUnit .SECONDS );
12111219
12121220 verify (mockStream2 ).start (any (ClientStreamListener .class ));
12131221 verify (retriableStreamRecorder ).postCommit ();
@@ -1260,7 +1268,7 @@ public void perRpcBufferLimitExceededDuringBackoff() {
12601268 bufferSizeTracer .outboundWireSize (2 );
12611269 verify (retriableStreamRecorder , never ()).postCommit ();
12621270
1263- fakeClock .forwardTime (( long ) ( INITIAL_BACKOFF_IN_SECONDS * FAKE_RANDOM ), TimeUnit .SECONDS );
1271+ fakeClock .forwardTime (calculateBackoffWithRetries ( 0 ), TimeUnit .SECONDS );
12641272 verify (mockStream2 ).start (any (ClientStreamListener .class ));
12651273 verify (mockStream2 ).isReady ();
12661274
@@ -1332,7 +1340,7 @@ public void expBackoff_maxBackoff_maxRetryAttempts() {
13321340 sublistenerCaptor1 .getValue ().closed (
13331341 Status .fromCode (RETRIABLE_STATUS_CODE_1 ), PROCESSED , new Metadata ());
13341342 assertEquals (1 , fakeClock .numPendingTasks ());
1335- fakeClock .forwardTime (( long ) ( INITIAL_BACKOFF_IN_SECONDS * FAKE_RANDOM ) - 1L , TimeUnit .SECONDS );
1343+ fakeClock .forwardTime (calculateBackoffWithRetries ( 0 ) - 1L , TimeUnit .SECONDS );
13361344 assertEquals (1 , fakeClock .numPendingTasks ());
13371345 fakeClock .forwardTime (1L , TimeUnit .SECONDS );
13381346 assertEquals (0 , fakeClock .numPendingTasks ());
@@ -1347,9 +1355,7 @@ public void expBackoff_maxBackoff_maxRetryAttempts() {
13471355 sublistenerCaptor2 .getValue ().closed (
13481356 Status .fromCode (RETRIABLE_STATUS_CODE_2 ), PROCESSED , new Metadata ());
13491357 assertEquals (1 , fakeClock .numPendingTasks ());
1350- fakeClock .forwardTime (
1351- (long ) (INITIAL_BACKOFF_IN_SECONDS * BACKOFF_MULTIPLIER * FAKE_RANDOM ) - 1L ,
1352- TimeUnit .SECONDS );
1358+ fakeClock .forwardTime (calculateBackoffWithRetries (1 ) - 1L , TimeUnit .SECONDS );
13531359 assertEquals (1 , fakeClock .numPendingTasks ());
13541360 fakeClock .forwardTime (1L , TimeUnit .SECONDS );
13551361 assertEquals (0 , fakeClock .numPendingTasks ());
@@ -1364,10 +1370,7 @@ public void expBackoff_maxBackoff_maxRetryAttempts() {
13641370 sublistenerCaptor3 .getValue ().closed (
13651371 Status .fromCode (RETRIABLE_STATUS_CODE_1 ), PROCESSED , new Metadata ());
13661372 assertEquals (1 , fakeClock .numPendingTasks ());
1367- fakeClock .forwardTime (
1368- (long ) (INITIAL_BACKOFF_IN_SECONDS * BACKOFF_MULTIPLIER * BACKOFF_MULTIPLIER * FAKE_RANDOM )
1369- - 1L ,
1370- TimeUnit .SECONDS );
1373+ fakeClock .forwardTime (calculateBackoffWithRetries (2 ) - 1L , TimeUnit .SECONDS );
13711374 assertEquals (1 , fakeClock .numPendingTasks ());
13721375 fakeClock .forwardTime (1L , TimeUnit .SECONDS );
13731376 assertEquals (0 , fakeClock .numPendingTasks ());
@@ -1382,7 +1385,7 @@ public void expBackoff_maxBackoff_maxRetryAttempts() {
13821385 sublistenerCaptor4 .getValue ().closed (
13831386 Status .fromCode (RETRIABLE_STATUS_CODE_2 ), PROCESSED , new Metadata ());
13841387 assertEquals (1 , fakeClock .numPendingTasks ());
1385- fakeClock .forwardTime (( long ) ( MAX_BACKOFF_IN_SECONDS * FAKE_RANDOM ) - 1L , TimeUnit .SECONDS );
1388+ fakeClock .forwardTime (calculateMaxBackoff ( ) - 1L , TimeUnit .SECONDS );
13861389 assertEquals (1 , fakeClock .numPendingTasks ());
13871390 fakeClock .forwardTime (1L , TimeUnit .SECONDS );
13881391 assertEquals (0 , fakeClock .numPendingTasks ());
@@ -1397,7 +1400,7 @@ public void expBackoff_maxBackoff_maxRetryAttempts() {
13971400 sublistenerCaptor5 .getValue ().closed (
13981401 Status .fromCode (RETRIABLE_STATUS_CODE_2 ), PROCESSED , new Metadata ());
13991402 assertEquals (1 , fakeClock .numPendingTasks ());
1400- fakeClock .forwardTime (( long ) ( MAX_BACKOFF_IN_SECONDS * FAKE_RANDOM ) - 1L , TimeUnit .SECONDS );
1403+ fakeClock .forwardTime (calculateMaxBackoff ( ) - 1L , TimeUnit .SECONDS );
14011404 assertEquals (1 , fakeClock .numPendingTasks ());
14021405 fakeClock .forwardTime (1L , TimeUnit .SECONDS );
14031406 assertEquals (0 , fakeClock .numPendingTasks ());
@@ -1480,7 +1483,7 @@ public void pushback() {
14801483 sublistenerCaptor3 .getValue ().closed (
14811484 Status .fromCode (RETRIABLE_STATUS_CODE_1 ), PROCESSED , new Metadata ());
14821485 assertEquals (1 , fakeClock .numPendingTasks ());
1483- fakeClock .forwardTime (( long ) ( INITIAL_BACKOFF_IN_SECONDS * FAKE_RANDOM ) - 1L , TimeUnit .SECONDS );
1486+ fakeClock .forwardTime (calculateBackoffWithRetries ( 0 ) - 1L , TimeUnit .SECONDS );
14841487 assertEquals (1 , fakeClock .numPendingTasks ());
14851488 fakeClock .forwardTime (1L , TimeUnit .SECONDS );
14861489 assertEquals (0 , fakeClock .numPendingTasks ());
@@ -1495,9 +1498,7 @@ public void pushback() {
14951498 sublistenerCaptor4 .getValue ().closed (
14961499 Status .fromCode (RETRIABLE_STATUS_CODE_2 ), PROCESSED , new Metadata ());
14971500 assertEquals (1 , fakeClock .numPendingTasks ());
1498- fakeClock .forwardTime (
1499- (long ) (INITIAL_BACKOFF_IN_SECONDS * BACKOFF_MULTIPLIER * FAKE_RANDOM ) - 1L ,
1500- TimeUnit .SECONDS );
1501+ fakeClock .forwardTime (calculateBackoffWithRetries (1 ) - 1L , TimeUnit .SECONDS );
15011502 assertEquals (1 , fakeClock .numPendingTasks ());
15021503 fakeClock .forwardTime (1L , TimeUnit .SECONDS );
15031504 assertEquals (0 , fakeClock .numPendingTasks ());
@@ -1512,10 +1513,7 @@ public void pushback() {
15121513 sublistenerCaptor5 .getValue ().closed (
15131514 Status .fromCode (RETRIABLE_STATUS_CODE_2 ), PROCESSED , new Metadata ());
15141515 assertEquals (1 , fakeClock .numPendingTasks ());
1515- fakeClock .forwardTime (
1516- (long ) (INITIAL_BACKOFF_IN_SECONDS * BACKOFF_MULTIPLIER * BACKOFF_MULTIPLIER * FAKE_RANDOM )
1517- - 1L ,
1518- TimeUnit .SECONDS );
1516+ fakeClock .forwardTime (calculateBackoffWithRetries (2 ) - 1L , TimeUnit .SECONDS );
15191517 assertEquals (1 , fakeClock .numPendingTasks ());
15201518 fakeClock .forwardTime (1L , TimeUnit .SECONDS );
15211519 assertEquals (0 , fakeClock .numPendingTasks ());
@@ -1804,7 +1802,7 @@ public void transparentRetry_onlyOnceOnRefused() {
18041802 .closed (Status .fromCode (RETRIABLE_STATUS_CODE_1 ), REFUSED , new Metadata ());
18051803
18061804 assertEquals (1 , fakeClock .numPendingTasks ());
1807- fakeClock .forwardTime (( long ) ( INITIAL_BACKOFF_IN_SECONDS * FAKE_RANDOM ), TimeUnit .SECONDS );
1805+ fakeClock .forwardTime (calculateBackoffWithRetries ( 0 ), TimeUnit .SECONDS );
18081806 inOrder .verify (retriableStreamRecorder ).newSubstream (1 );
18091807 ArgumentCaptor <ClientStreamListener > sublistenerCaptor3 =
18101808 ArgumentCaptor .forClass (ClientStreamListener .class );
@@ -1907,7 +1905,7 @@ public void normalRetry_thenNoTransparentRetry_butNormalRetry() {
19071905 .closed (Status .fromCode (RETRIABLE_STATUS_CODE_1 ), PROCESSED , new Metadata ());
19081906
19091907 assertEquals (1 , fakeClock .numPendingTasks ());
1910- fakeClock .forwardTime (( long ) ( INITIAL_BACKOFF_IN_SECONDS * FAKE_RANDOM ), TimeUnit .SECONDS );
1908+ fakeClock .forwardTime (calculateBackoffWithRetries ( 0 ), TimeUnit .SECONDS );
19111909 inOrder .verify (retriableStreamRecorder ).newSubstream (1 );
19121910 ArgumentCaptor <ClientStreamListener > sublistenerCaptor2 =
19131911 ArgumentCaptor .forClass (ClientStreamListener .class );
@@ -1923,8 +1921,7 @@ public void normalRetry_thenNoTransparentRetry_butNormalRetry() {
19231921 .closed (Status .fromCode (RETRIABLE_STATUS_CODE_1 ), REFUSED , new Metadata ());
19241922
19251923 assertEquals (1 , fakeClock .numPendingTasks ());
1926- fakeClock .forwardTime (
1927- (long ) (INITIAL_BACKOFF_IN_SECONDS * BACKOFF_MULTIPLIER * FAKE_RANDOM ), TimeUnit .SECONDS );
1924+ fakeClock .forwardTime (calculateBackoffWithRetries (1 ), TimeUnit .SECONDS );
19281925 inOrder .verify (retriableStreamRecorder ).newSubstream (2 );
19291926 ArgumentCaptor <ClientStreamListener > sublistenerCaptor3 =
19301927 ArgumentCaptor .forClass (ClientStreamListener .class );
@@ -1960,7 +1957,7 @@ public void normalRetry_thenNoTransparentRetry_andNoMoreRetry() {
19601957 .closed (Status .fromCode (RETRIABLE_STATUS_CODE_1 ), PROCESSED , new Metadata ());
19611958
19621959 assertEquals (1 , fakeClock .numPendingTasks ());
1963- fakeClock .forwardTime (( long ) ( INITIAL_BACKOFF_IN_SECONDS * FAKE_RANDOM ), TimeUnit .SECONDS );
1960+ fakeClock .forwardTime (calculateBackoffWithRetries ( 0 ), TimeUnit .SECONDS );
19641961 inOrder .verify (retriableStreamRecorder ).newSubstream (1 );
19651962 ArgumentCaptor <ClientStreamListener > sublistenerCaptor2 =
19661963 ArgumentCaptor .forClass (ClientStreamListener .class );
0 commit comments