From e80a05c38e5f77b754d520af12c0feb4ed387466 Mon Sep 17 00:00:00 2001 From: Kashif Faraz Date: Mon, 16 Dec 2024 23:40:13 -0800 Subject: [PATCH] Add test and comments for RetryUtils.nextSleep (#17556) --- .../druid/java/util/common/RetryUtils.java | 20 +++++++++++++++ .../java/util/common/RetryUtilsTest.java | 25 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/processing/src/main/java/org/apache/druid/java/util/common/RetryUtils.java b/processing/src/main/java/org/apache/druid/java/util/common/RetryUtils.java index 98c422b1dca..a94f8d1df7b 100644 --- a/processing/src/main/java/org/apache/druid/java/util/common/RetryUtils.java +++ b/processing/src/main/java/org/apache/druid/java/util/common/RetryUtils.java @@ -206,9 +206,29 @@ public class RetryUtils Thread.sleep(sleepMillis); } + /** + * Calculates the duration in milliseconds to sleep before the next attempt of + * a retryable operation. The duration is calculated in an exponential back-off + * manner with a fuzzy multiplier to introduce some variance. + *

+ * Sleep duration in milliseconds for subsequent retries: + *

+ * + * @param nTry Index of the next retry, starting with 1 + * @return Next sleep duration in the range [0, 120,000] millis + */ public static long nextRetrySleepMillis(final int nTry) { + // fuzzyMultiplier in [0, 2] final double fuzzyMultiplier = Math.min(Math.max(1 + 0.2 * ThreadLocalRandom.current().nextGaussian(), 0), 2); + + // sleepMillis in [1 x 2^(nTry-1), 60] * [0, 2] seconds final long sleepMillis = (long) (Math.min(MAX_SLEEP_MILLIS, BASE_SLEEP_MILLIS * Math.pow(2, nTry - 1)) * fuzzyMultiplier); return sleepMillis; diff --git a/processing/src/test/java/org/apache/druid/java/util/common/RetryUtilsTest.java b/processing/src/test/java/org/apache/druid/java/util/common/RetryUtilsTest.java index 7df0aa0687c..8d0271397d7 100644 --- a/processing/src/test/java/org/apache/druid/java/util/common/RetryUtilsTest.java +++ b/processing/src/test/java/org/apache/druid/java/util/common/RetryUtilsTest.java @@ -186,4 +186,29 @@ public class RetryUtilsTest Assert.assertEquals(result, "hey"); Assert.assertEquals("count", 2, count.get()); } + + @Test + public void testNextRetrySleepMillis() + { + long totalSleepTimeMillis = 0; + + for (int i = 1; i < 7; ++i) { + final long nextSleepMillis = RetryUtils.nextRetrySleepMillis(i); + Assert.assertTrue(nextSleepMillis >= 0); + Assert.assertTrue(nextSleepMillis <= (2_000 * Math.pow(2, i - 1))); + + totalSleepTimeMillis += nextSleepMillis; + } + + for (int i = 7; i < 11; ++i) { + final long nextSleepMillis = RetryUtils.nextRetrySleepMillis(i); + Assert.assertTrue(nextSleepMillis >= 0); + Assert.assertTrue(nextSleepMillis <= 120_000); + + totalSleepTimeMillis += nextSleepMillis; + } + + Assert.assertTrue(totalSleepTimeMillis > 3 * 60_000); + Assert.assertTrue(totalSleepTimeMillis < 8 * 60_000); + } }