Resilience

resilience2RetryWithBackoff

Path
pkg18resiliencepatterns/resilience2RetryWithBackoff.java
Package
pkg18resiliencepatterns
Study order
2
Run
Single-file source launch
Command
java pkg18resiliencepatterns/resilience2RetryWithBackoff.java

There is no in-browser runner. This is the file from the curriculum, unchanged.

pkg18resiliencepatterns/resilience2RetryWithBackoff.java
1package pkg18resiliencepatterns;2 3import java.time.Duration;4import java.util.concurrent.ThreadLocalRandom;5import java.util.function.Supplier;6 7/*8 * resilience2RetryWithBackoff.java9 * --------------------------------10 * Retry with exponential backoff + jitter: recover from transient failures.11 *12 * DEFINITION:13 *   Retry re-executes a failed operation. Backoff increases delay between tries;14 *   jitter randomizes delay to prevent synchronized retries (thundering herd).15 *16 * KEY POINTS:17 *   - Only retry transient errors (timeouts, 503), not business failures.18 *   - Cap max attempts and max delay.19 *   - Idempotent operations are safe to retry.20 */21public class resilience2RetryWithBackoff {22 23    static <T> T retry(Supplier<T> action, int maxAttempts, Duration initialDelay, Duration maxDelay) {24        Duration delay = initialDelay;25        for (int attempt = 1; attempt <= maxAttempts; attempt++) {26            try {27                return action.get();28            } catch (RuntimeException e) {29                if (attempt == maxAttempts) throw e;30                long jitter = ThreadLocalRandom.current().nextLong(delay.toMillis() / 2, delay.toMillis());31                System.out.printf("  attempt %d failed (%s), retry in %d ms%n", attempt, e.getMessage(), jitter);32                try { Thread.sleep(jitter); } catch (InterruptedException ie) {33                    Thread.currentThread().interrupt();34                    throw new RuntimeException(ie);35                }36                delay = Duration.ofMillis(Math.min(delay.toMillis() * 2, maxDelay.toMillis()));37            }38        }39        throw new IllegalStateException("unreachable");40    }41 42    public static void main(String[] args) {43        java.util.concurrent.atomic.AtomicInteger calls = new java.util.concurrent.atomic.AtomicInteger();44 45        String result = retry(() -> {46            int n = calls.incrementAndGet();47            if (n <= 2) throw new RuntimeException("timeout");48            return "ok on attempt " + n;49        }, 5, Duration.ofMillis(50), Duration.ofMillis(400));50 51        System.out.println("Result: " + result);52    }53}