diff options
author | Martin Polden <mpolden@mpolden.no> | 2024-03-05 14:42:05 +0100 |
---|---|---|
committer | Martin Polden <mpolden@mpolden.no> | 2024-03-05 14:44:45 +0100 |
commit | e8e099766712a504bda2a96e664265cd77a3c223 (patch) | |
tree | 606664971d39599dfdcb3b24a379210bc151f245 /vespajlib | |
parent | 65c1240681f7e4d091776974a2f4348937d00d75 (diff) |
Move ExponentialBackoff to vespajlib
Diffstat (limited to 'vespajlib')
-rw-r--r-- | vespajlib/src/main/java/com/yahoo/time/ExponentialBackoff.java | 47 | ||||
-rw-r--r-- | vespajlib/src/test/java/com/yahoo/time/ExponentialBackoffTest.java | 31 |
2 files changed, 78 insertions, 0 deletions
diff --git a/vespajlib/src/main/java/com/yahoo/time/ExponentialBackoff.java b/vespajlib/src/main/java/com/yahoo/time/ExponentialBackoff.java new file mode 100644 index 00000000000..95926a143e0 --- /dev/null +++ b/vespajlib/src/main/java/com/yahoo/time/ExponentialBackoff.java @@ -0,0 +1,47 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.time; + +import java.time.Duration; +import java.util.Random; + +/** + * Calculate a delay using an exponential backoff algorithm. Based on ExponentialBackOff in google-http-client. + * + * @author mpolden + */ +public class ExponentialBackoff { + + private static final double RANDOMIZATION_FACTOR = 0.5; + + private final Duration initialDelay; + private final Duration maxDelay; + private final Random random; + + public ExponentialBackoff(Duration initialDelay, Duration maxDelay) { + this(initialDelay, maxDelay, new Random()); + } + + ExponentialBackoff(Duration initialDelay, Duration maxDelay, Random random) { + this.initialDelay = requireNonNegative(initialDelay); + this.maxDelay = requireNonNegative(maxDelay); + this.random = random; + } + + /** Return the delay of given attempt */ + public Duration delay(int attempt) { + if (attempt < 1) throw new IllegalArgumentException("Attempt must be positive"); + double currentDelay = attempt * initialDelay.toMillis(); + double delta = RANDOMIZATION_FACTOR * currentDelay; + double lowerDelay = currentDelay - delta; + double upperDelay = currentDelay + delta; + long millis = (long) Math.min(lowerDelay + (random.nextDouble() * (upperDelay - lowerDelay + 1)), + maxDelay.toMillis()); + return Duration.ofMillis(millis); + } + + private static Duration requireNonNegative(Duration d) { + if (d.isNegative()) throw new IllegalArgumentException("Invalid duration: " + d); + return d; + } + +} diff --git a/vespajlib/src/test/java/com/yahoo/time/ExponentialBackoffTest.java b/vespajlib/src/test/java/com/yahoo/time/ExponentialBackoffTest.java new file mode 100644 index 00000000000..07295891cd0 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/time/ExponentialBackoffTest.java @@ -0,0 +1,31 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.time; + +import org.junit.Test; + +import java.time.Duration; +import java.util.List; +import java.util.Random; +import java.util.stream.IntStream; + +import static org.junit.Assert.assertEquals; + +/** + * @author mpolden + */ +public class ExponentialBackoffTest { + + @Test + public void delay() { + ExponentialBackoff b = new ExponentialBackoff(Duration.ofSeconds(1), Duration.ofSeconds(10), new Random(1000)); + assertEquals(List.of(Duration.ofMillis(1210), + Duration.ofMillis(2150), + Duration.ofMillis(4340), + Duration.ofMillis(2157), + Duration.ofMillis(4932)), + IntStream.rangeClosed(1, 5) + .mapToObj(b::delay) + .toList()); + } + +} |