marisbest2
marisbest2

Reputation: 1356

Java 8 generic Retry if specific exception

I'm finding myself writing alot of retry loops that look like

    int triesRemaining = 3;

    while (triesRemaining > 0) {
        try {
            <MY FUNCTION CALL>
            LOGGER.info("success");
            break;
        } catch (Exception e) {
            if (e.getCause() instanceof SocketTimeoutException) {
                triesRemaining--;
                LOGGER.info(e.getMessage() + " trying again. Tries Remaining: " + triesRemaining);
            } else {
                LOGGER.error(e.getMessage(), e);
                return;
            }
        }
    }
    if (triesRemaining == 0) {
        LOGGER.error("Failed over too many times");
    }

I want to write a generic function that accepts a Lambda and only retries on a specific error (in the above case thats SocketTimeoutException). I've seen some functions that accept a Runnable which is fine, but they don't seem to allow limiting to specific exceptions.

Any advice?

Upvotes: 1

Views: 5442

Answers (5)

Andremoniy
Andremoniy

Reputation: 34900

What's the problem of just making this function to accept a Runnable argument and then run it in <MY FUNCTION CALL>?

public static void retry(Runnable r) {
      // ...
      while (triesRemaining > 0) {
        try {
            r.run();
            LOGGER.info("success");
            break;
        } 
      // ...
}

then call it (if you prefer - with a lambda):

    retry(() -> {
        connectToServer();
        // todo what-ever-you-want
    });

Upvotes: 1

Josh Stone
Josh Stone

Reputation: 4448

Check out Failsafe:

RetryPolicy retryPolicy = new RetryPolicy()
  .retryOn(SocketTimeoutException.class)
  .withMaxRetries(3);

Failsafe.with(retryPolicy)
  .onRetry((c, f, ctx) -> log.warn("Failure #{}. Retrying.", ctx.getExecutions()))
  .onFailure(e -> LOGGER.error(e.getMessage(), e))
  .run(() -> myFunctionCall());

Upvotes: 1

Shubham Chaurasia
Shubham Chaurasia

Reputation: 2622

Well it's already done. It also accepts list of exceptions on which you want to retry. It also provides linear/exponential retry strategies. Have a look https://github.com/rholder/guava-retrying

A simple example from it's readme, you can compose and use a retryer 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();
}

Upvotes: 2

fabfas
fabfas

Reputation: 2228

I believe you're looking for pure Java based solution. Based on assumption, I would say Java 8 uses functional interface, an interface with single abstract method. I would create a new RetryCommand class that has a run method which takes in a function.

Upvotes: 0

Fabien Leborgne
Fabien Leborgne

Reputation: 387

Have a look to org.springframework.retry

There is an annotation @Retryable which corresponding to your need. You can specify the type of exception to retry and configure the number of attempt, etc...

Upvotes: 1

Related Questions