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
}