@Override public TimedAttemptSettings createNextAttempt( Throwable prevThrowable, ResponseT prevResponse, TimedAttemptSettings prevSettings) { if (prevThrowable != null && prevThrowable instanceof DeadlineExceededException) { return TimedAttemptSettings.newBuilder() .setGlobalSettings(prevSettings.getGlobalSettings()) .setRetryDelay(prevSettings.getRetryDelay()) .setRpcTimeout(prevSettings.getRpcTimeout()) .setRandomizedRetryDelay(DEADLINE_SLEEP_DURATION) .setAttemptCount(prevSettings.getAttemptCount() + 1) .setFirstAttemptStartTimeNanos(prevSettings.getFirstAttemptStartTimeNanos()) .build(); } return null; }
protected Long getNextBackoff() { if (currentBackoff == null) { // Historically, the client waited for "total timeout" after the first failure. For now, // that behavior is preserved, even though that's not the ideal. // // TODO: Think through retries, and create policy that works with the mental model most // users would have of relating to retries. That would likely involve updating some // default settings in addition to changing the algorithm. currentBackoff = exponentialRetryAlgorithm.createFirstAttempt(); } currentBackoff = exponentialRetryAlgorithm.createNextAttempt(currentBackoff); if (!exponentialRetryAlgorithm.shouldRetry(currentBackoff)) { // TODO: consider creating a subclass of exponentialRetryAlgorithm to encapsulate this logic long timeLeftNs = currentBackoff.getGlobalSettings().getTotalTimeout().toNanos() - (clock.nanoTime() - currentBackoff.getFirstAttemptStartTimeNanos()); long timeLeftMs = TimeUnit.NANOSECONDS.toMillis(timeLeftNs); if (timeLeftMs > currentBackoff.getGlobalSettings().getInitialRetryDelay().toMillis()) { // The backoff algorithm doesn't always wait until the timeout is achieved. Wait // one final time so that retries hit return timeLeftMs; } else { // Finish for real. return null; } } else { return currentBackoff.getRetryDelay().toMillis(); } }
@Override public TimedAttemptSettings createNextAttempt( Throwable prevThrowable, ResponseT prevResponse, TimedAttemptSettings prevSettings) { if (prevThrowable != null && prevThrowable instanceof DeadlineExceededException) { return TimedAttemptSettings.newBuilder() .setGlobalSettings(prevSettings.getGlobalSettings()) .setRetryDelay(prevSettings.getRetryDelay()) .setRpcTimeout(prevSettings.getRpcTimeout()) .setRandomizedRetryDelay(DEADLINE_SLEEP_DURATION) .setAttemptCount(prevSettings.getAttemptCount() + 1) .setFirstAttemptStartTimeNanos(prevSettings.getFirstAttemptStartTimeNanos()) .build(); } return null; }
@Test public void testCreateFirstAttempt() { TimedAttemptSettings attempt = algorithm.createFirstAttempt(); // Checking only the most core values, to not make this test too implementation specific. assertEquals(0, attempt.getAttemptCount()); assertEquals(0, attempt.getOverallAttemptCount()); assertEquals(Duration.ZERO, attempt.getRetryDelay()); assertEquals(Duration.ZERO, attempt.getRandomizedRetryDelay()); assertEquals(Duration.ofMillis(1L), attempt.getRpcTimeout()); assertEquals(Duration.ZERO, attempt.getRetryDelay()); }
if (prevSettings.getAttemptCount() > 0) { newRetryDelay = (long) (settings.getRetryDelayMultiplier() * prevSettings.getRetryDelay().toMillis()); newRetryDelay = Math.min(newRetryDelay, settings.getMaxRetryDelay().toMillis());
if (prevSettings.getAttemptCount() > 0) { newRetryDelay = (long) (settings.getRetryDelayMultiplier() * prevSettings.getRetryDelay().toMillis()); newRetryDelay = Math.min(newRetryDelay, settings.getMaxRetryDelay().toMillis());
@Test public void testCreateNextAttempt() { TimedAttemptSettings firstAttempt = algorithm.createFirstAttempt(); TimedAttemptSettings secondAttempt = algorithm.createNextAttempt(firstAttempt); // Checking only the most core values, to not make this test too implementation specific. assertEquals(1, secondAttempt.getAttemptCount()); assertEquals(1, secondAttempt.getOverallAttemptCount()); assertEquals(Duration.ofMillis(1L), secondAttempt.getRetryDelay()); assertEquals(Duration.ofMillis(1L), secondAttempt.getRandomizedRetryDelay()); assertEquals(Duration.ofMillis(2L), secondAttempt.getRpcTimeout()); TimedAttemptSettings thirdAttempt = algorithm.createNextAttempt(secondAttempt); assertEquals(2, thirdAttempt.getAttemptCount()); assertEquals(Duration.ofMillis(2L), thirdAttempt.getRetryDelay()); assertEquals(Duration.ofMillis(2L), thirdAttempt.getRandomizedRetryDelay()); assertEquals(Duration.ofMillis(4L), thirdAttempt.getRpcTimeout()); }