How to Retry a Task in Java using Guava's Retryer
We can use Guava’s Retryer to execute some task in a loop until a specified predicate resolves.
Suppose we want to run this function until it returns true
.
boolean getData() {
if (/* Maybe some API call */) {
return true;
}
return false;
}
1. Build the Retryer
Let’s start by building the Retryer
.
Here are some basic definitions:
- A retryer executes a function and retries it until it succeeds.
- A wait strategy indicates how long to sleep between attempts.
- A stop strategy indicates when to stop retrying.
Retryer<Boolean> retryer = RetryerBuilder
.<Boolean>newBuilder()
.withStopStrategy(StopStrategies.stopAfterDelay(20, TimeUnit.SECONDS))
.withWaitStrategy(WaitStrategies.fixedWait(2, TimeUnit.SECONDS))
.retryIfResult(Boolean.FALSE::equals)
.retryIfException()
.build();
Retryer. Here, we’re specifying that we want to run some function until it returns true
(i.e. our “successful” state).
Wait strategy. If the result of the function returns false
, we’ll want to retry after the specified wait strategy (i.e. 2
seconds).
Stop strategy. We’ll continue to retry this function until it returns true
or until we reach the stop strategy (i.e. 20
seconds).
Note that we can also retry if the result of the callable is null using
retryIfResult(Predicates.<Boolean>isNull())
.
Various wait and stop strategies
We can also use different wait strategies.
WaitStrategies.noWait()
WaitStrategies.fixedWait(1, TimeUnit.SECONDS)
WaitStrategies.randomWait(1, TimeUnit.SECONDS, 10, TimeUnit.SECONDS)
WaitStrategies.incrementingWait(1, TimeUnit.SECONDS, 1, TimeUnit.SECONDS)
WaitStrategies.exponentialWait(10, TimeUnit.SECONDS)
WaitStrategies.fibonacciWait(2, 10, TimeUnit.SECONDS)
WaitStrategies.exceptionWait(Class<T> exceptionClass, Function<T, Long> function)
WaitStrategies.join(WaitStrategy... waitStrategies)
And different stop strategies.
StopStrategies.stopAfterDelay(20, TimeUnit.SECONDS)
StopStrategies.stopAfterAttempt(3)
StopStrategies.neverStop()
2. Run code using Retryer
We’ll execute our task inside a try-catch
block, allowing us to handle ExecutionException
and RetryException
errors.
try {
retryer.call(() -> getData());
} catch (ExecutionException e) {
// Encountered exception during retry attempt
} catch (RetryException e) {
// Failed after hitting stop strategy
}