com.github.davidmoten.aws.lw.client.internal.Retries Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aws-lightweight-client-java Show documentation
Show all versions of aws-lightweight-client-java Show documentation
Lightweight client for all AWS services (but still with useful builders and XML parser)
The newest version!
package com.github.davidmoten.aws.lw.client.internal;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.concurrent.Callable;
import java.util.function.Predicate;
import com.github.davidmoten.aws.lw.client.MaxAttemptsExceededException;
import com.github.davidmoten.aws.lw.client.internal.util.Preconditions;
public final class Retries {
private final long initialIntervalMs;
private final int maxAttempts;
private final double backoffFactor;
private final long maxIntervalMs;
private final double jitter;
private final Predicate super T> valueShouldRetry;
private final Predicate super Throwable> throwableShouldRetry;
public Retries(long initialIntervalMs, int maxAttempts, double backoffFactor, double jitter, long maxIntervalMs,
Predicate super T> valueShouldRetry, Predicate super Throwable> throwableShouldRetry) {
Preconditions.checkArgument(jitter >= 0 && jitter <= 1, "jitter must be between 0 and 1 inclusive");
this.initialIntervalMs = initialIntervalMs;
this.maxAttempts = maxAttempts;
this.backoffFactor = backoffFactor;
this.jitter = jitter;
this.maxIntervalMs = maxIntervalMs;
this.valueShouldRetry = valueShouldRetry;
this.throwableShouldRetry = throwableShouldRetry;
}
public static Retries create(Predicate super T> valueShouldRetry,
Predicate super Throwable> throwableShouldRetry) {
return new Retries( //
100, //
4, //
2.0, //
0.0, // no jitter
20000, //
valueShouldRetry, //
throwableShouldRetry);
}
public T call(Callable callable) {
return call(callable, valueShouldRetry);
}
public S call(Callable callable, Predicate super S> valueShouldRetry) {
long intervalMs = initialIntervalMs;
int attempt = 0;
while (true) {
S value;
try {
attempt++;
value = callable.call();
if (!valueShouldRetry.test(value)) {
return value;
}
if (reachedMaxAttempts(attempt, maxAttempts)) {
// note that caller is not aware that maxAttempts were reached, the caller just
// receives the last error response
return value;
}
} catch (Throwable t) {
if (!throwableShouldRetry.test(t)) {
rethrow(t);
}
if (reachedMaxAttempts(attempt, maxAttempts)) {
throw new MaxAttemptsExceededException("exceeded max attempts " + maxAttempts, t);
}
}
sleep(intervalMs);
//calculate the interval for the next retry
intervalMs = Math.round(backoffFactor * intervalMs);
if (maxIntervalMs > 0) {
intervalMs = Math.min(maxIntervalMs, intervalMs);
}
// apply jitter (if 0 then no change)
intervalMs = Math.round((1 - jitter * Math.random()) * intervalMs);
}
}
// VisibleForTesting
static boolean reachedMaxAttempts(int attempt, int maxAttempts) {
return maxAttempts > 0 && attempt >= maxAttempts;
}
static void sleep(long intervalMs) {
try {
Thread.sleep(intervalMs);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public Retries withValueShouldRetry(Predicate super S> valueShouldRetry) {
return new Retries(initialIntervalMs, maxAttempts, backoffFactor, jitter, maxIntervalMs, valueShouldRetry,
throwableShouldRetry);
}
public Retries withInitialIntervalMs(long initialIntervalMs) {
return new Retries(initialIntervalMs, maxAttempts, backoffFactor, jitter, maxIntervalMs, valueShouldRetry,
throwableShouldRetry);
}
public Retries withMaxAttempts(int maxAttempts) {
return new Retries(initialIntervalMs, maxAttempts, backoffFactor, jitter, maxIntervalMs, valueShouldRetry,
throwableShouldRetry);
}
public Retries withBackoffFactor(double backoffFactor) {
return new Retries(initialIntervalMs, maxAttempts, backoffFactor, jitter, maxIntervalMs, valueShouldRetry,
throwableShouldRetry);
}
public Retries withMaxIntervalMs(long maxIntervalMs) {
return new Retries(initialIntervalMs, maxAttempts, backoffFactor, jitter, maxIntervalMs, valueShouldRetry,
throwableShouldRetry);
}
public Retries withJitter(double jitter) {
return new Retries(initialIntervalMs, maxAttempts, backoffFactor, jitter, maxIntervalMs, valueShouldRetry,
throwableShouldRetry);
}
public Retries withThrowableShouldRetry(Predicate super Throwable> throwableShouldRetry) {
return new Retries(initialIntervalMs, maxAttempts, backoffFactor, jitter, maxIntervalMs, valueShouldRetry,
throwableShouldRetry);
}
public Retries copy() {
return new Retries<>(initialIntervalMs, maxAttempts, backoffFactor, jitter, maxIntervalMs, valueShouldRetry,
throwableShouldRetry);
}
// VisibleForTesting
static void rethrow(Throwable t) throws Error {
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else if (t instanceof Error) {
throw (Error) t;
} else if (t instanceof IOException) {
throw new UncheckedIOException((IOException) t);
} else {
throw new RuntimeException(t);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy