Website: github.com/nurkiewicz/async-retry
Slides: nurkiewicz.github.io/talks
ScheduledExecutorService scheduler = //...
RetryExecutor executor = new AsyncRetryExecutor(scheduler);
CompletableFuture<Socket> future = executor.getWithRetry(() ->
new Socket("localhost", 8080)
);
future.thenAccept(socket ->
System.out.println("Connected! " + socket)
);
TRACE Retry 0 failed after 3ms, scheduled next retry in 508ms (Sun Jul 21 21:01:12 CEST 2013)
java.net.ConnectException: Connection refused
...
TRACE Retry 1 failed after 0ms, scheduled next retry in 934ms (Sun Jul 21 21:01:13 CEST 2013)
java.net.ConnectException: Connection refused
...
TRACE Retry 2 failed after 0ms, scheduled next retry in 1919ms (Sun Jul 21 21:01:15 CEST 2013)
java.net.ConnectException: Connection refused
...
TRACE Successful after 2 retries, took 0ms and returned: Socket[addr=localhost/127.0.0.1,port=8080,localport=46332]
Connected! Socket[addr=localhost/127.0.0.1,port=8080,localport=46332]
ScheduledExecutorService scheduler =
Executors.newSingleThreadScheduledExecutor();
RetryExecutor executor = new AsyncRetryExecutor(scheduler)
.retryOn(SocketException.class)
.withExponentialBackoff(500, 2) //500ms times 2 after each retry
.withUniformJitter() //add between +/- 100 ms randomly
.withMaxDelay(10_000) //10 seconds
.withMaxRetries(20);
See also: RetryTemplate
from Spring
CompletableFuture<String> f1 =
executor.getWithRetry(ctx -> unreliable());
CompletableFuture<String> f2 =
executor.getWithRetry(ctx -> slow());
f1.acceptEither(f2, first -> {
//first to succeed
});
abortOn()
/ retryOn()
executor.
retryOn(IOException.class).
abortOn(FileNotFoundException.class).
retryOn(SQLException.class).
abortOn(DataTruncation.class).
getWithRetry(ctx -> dao.load(42));
OptimisticLock Exception
executor.
retryOn(OptimisticLockException.class).
withNoDelay().
getWithRetry(ctx -> dao.optimistic());
executor.
abortIf(throwable ->
throwable instanceof SQLException &&
throwable.getMessage().contains("ORA-00911")
).
retryIf(t -> t.getCause() != null);
executor.withUniformJitter(100) //ms
executor.withProportionalJitter(0.1) //10%
RetryContext
executor.
getWithRetry(ctx ->
new Socket("localhost",
8080 + ctx.getRetryCount())).
thenAccept(System.out::println);
@Bean
public RetryExecutor retryExecutor() {
return new AsyncRetryExecutor(scheduler()).
retryOn(SocketException.class).
withExponentialBackoff(500, 2);
}
@Bean(destroyMethod = "shutdownNow")
public ScheduledExecutorService scheduler() {
return Executors.newSingleThreadScheduledExecutor();
}
<dependency>
<groupId>com.nurkiewicz.asyncretry</groupId>
<artifactId>asyncretry</artifactId>
<version>0.0.5</version>
</dependency>
Website: github.com/nurkiewicz/async-retry
Slides: nurkiewicz.github.io/talks