This is a personal maintenance version, which is not compatible with the API of the original library
Incompatible changes
- Package structure modification
- RetryListener now only calls back the onRetry method when a retry occurs
- Replace the project build tool from gradle to maven
- Package name from
com.github.rholder.retry.*
toio.github.itning.retry.*
The guava-retrying module provides a general purpose method for retrying arbitrary Java code with specific stop, retry, and exception handling capabilities that are enhanced by Guava's predicate matching.
This is a fork of the excellent RetryerBuilder code posted here by Jean-Baptiste Nizet (JB). I've added a Gradle build for pushing it up to my little corner of Maven Central so that others can easily pull it into their existing projects with minimal effort. It also includes exponential and Fibonacci backoff WaitStrategies that might be useful for situations where more well-behaved service polling is preferred.
<dependency>
<groupId>io.github.itning</groupId>
<artifactId>guava-retrying3</artifactId>
<version>3.0.4</version>
</dependency>
If you don't use io.github.itning.retry.strategy.limit.FixedAttemptTimeLimit
in your code, you can exclude guava
dependency
<dependency>
<groupId>io.github.itning</groupId>
<artifactId>guava-retrying3</artifactId>
<version>3.0.4</version>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
implementation "io.github.itning:guava-retrying3:3.0.4"
A minimal sample of some of the functionality would look like:
Callable<Boolean> callable = new Callable<Boolean>() {
public Boolean call() throws Exception {
return true; // do something useful here
}
};
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
.retryIfResult(Predicates.<Boolean>isNull())
.retryIfExceptionOfType(IOException.class)
.retryIfRuntimeException()
.withStopStrategy(StopStrategies.stopAfterAttempt(3))
.build();
try {
retryer.call(callable);
} catch (RetryException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
This will retry whenever the result of the Callable
is null, if an IOException
is thrown, or if any other
RuntimeException
is thrown from the call()
method. It will stop after attempting to retry 3 times and throw a
RetryException
that contains information about the last failed attempt. If any other Exception
pops out of the
call()
method it's wrapped and rethrown in an ExecutionException
.
Create a Retryer
that retries forever, waiting after every failed retry in increasing exponential backoff intervals
until at most 5 minutes. After 5 minutes, retry from then on in 5 minute intervals.
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
.retryIfExceptionOfType(IOException.class)
.retryIfRuntimeException()
.withWaitStrategy(WaitStrategies.exponentialWait(100, 5, TimeUnit.MINUTES))
.withStopStrategy(StopStrategies.neverStop())
.build();
You can read more about exponential backoff and the historic role it played in the development of TCP/IP in Congestion Avoidance and Control.
Create a Retryer
that retries forever, waiting after every failed retry in increasing Fibonacci backoff intervals
until at most 2 minutes. After 2 minutes, retry from then on in 2 minute intervals.
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
.retryIfExceptionOfType(IOException.class)
.retryIfRuntimeException()
.withWaitStrategy(WaitStrategies.fibonacciWait(100, 2, TimeUnit.MINUTES))
.withStopStrategy(StopStrategies.neverStop())
.build();
Similar to the ExponentialWaitStrategy
, the FibonacciWaitStrategy
follows a pattern of waiting an increasing amount
of time after each failed attempt.
Instead of an exponential function it's (obviously) using a Fibonacci sequence to calculate the wait time.
Depending on the problem at hand, the FibonacciWaitStrategy
might perform better and lead to better throughput than
the ExponentialWaitStrategy
- at least according to
A Performance Comparison of Different Backoff Algorithms under Different Rebroadcast Probabilities for MANETs.
The implementation of FibonacciWaitStrategy
is using an iterative version of the Fibonacci because a (naive) recursive
version will lead to a StackOverflowError
at a certain point (although very unlikely with useful parameters for retrying).
Inspiration for this implementation came from Efficient retry/backoff mechanisms.
The guava-retrying module uses a maven-based build system. The only prerequisites are Git and JDK 1.8+.
git clone git://github.com/itning/guava-retrying3.git
./mvn
./mvn install
The guava-retrying module is released under version 2.0 of the Apache License.
- Jean-Baptiste Nizet (JB)
- Jason Dunkelberger (dirkraft)
- Diwaker Gupta (diwakergupta)
- Jochen Schalanda (joschi)
- Shajahan Palayil (shasts)
- Olivier Grégoire (fror)
- Andrei Savu (andreisavu)
- (tchdp)
- (squalloser)
- Yaroslav Matveychuk (yaroslavm)
- Stephan Schroevers (Stephan202)
- Chad (voiceinsideyou)
- Kevin Conaway (kevinconaway)
- Alberto Scotto (alb-i986)