Retry a failing call with capped backoff
Java
import java.time.Duration;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Supplier;
/** Retries a flaky supplier with exponential backoff, jitter and a cap. */
public final class Retry {
private Retry() {
}
public static <T> T call(Supplier<T> action, int maxAttempts, Duration baseDelay)
throws InterruptedException {
RuntimeException last = null;
for (int attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return action.get();
} catch (RuntimeException e) {
last = e;
if (attempt == maxAttempts) {
break;
}
long backoff = Math.min(baseDelay.toMillis() << Math.min(attempt - 1, 10), 10_000L);
long jitter = ThreadLocalRandom.current().nextLong(0, backoff / 2 + 1);
Thread.sleep(backoff / 2 + jitter);
}
}
throw new IllegalStateException("all " + maxAttempts + " attempts failed", last);
}
public static void main(String[] args) throws InterruptedException {
int[] calls = {0};
String result = call(() -> {
if (calls[0]++ < 2) {
throw new IllegalStateException("transient error");
}
return "ok after " + calls[0] + " calls";
}, 5, Duration.ofMillis(50));
System.out.println(result); // ok after 3 calls
}
}