Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to simplify retry code block with java 8 features

Tags:

java

java-8

In my code I have a section which tries to connect to some external interface, if it fails, then it will retry it a fixed number of times. The code works, but is somewhat ugly. I am wondering whether this can be done in a more elegant way using some fancy Java8 features?

int count = 0;
final int maxRetries = 3;
while ( count < maxRetries )
{
   try
   {
     // Some Code
     // break out of loop on success
   }
   catch ( final ExecutionException e )
   {
      LOG.debug( "retrying..." );
      if ( ++count >= maxRetries )
      {
         LOG.debug( "do something else...");
         //do something else
      }
   }
}
like image 498
Moonlit Avatar asked Jun 29 '16 17:06

Moonlit


People also ask

How do you create a retry mechanism in Java?

A simple solution to implement retry logic in Java is to write your code inside a for loop that executes the specified number of times (the maximum retry value).

What is retry in Java?

Retry pattern consists retrying operations on remote resources over the network a set number of times.


2 Answers

What you can do is separate out the retry logic. You'll need some ancillary scaffolding:

interface ThrowingTask {
    void run() throws ExecutionException;
}

Now, you write:

boolean runWithRetries(int maxRetries, ThrowingTask t) { 
    int count = 0;
    while (count < maxRetries) {
        try {
            t.run();
            return true;
        }
        catch (ExecutionException e) {
            if (++count >= maxRetries)
                return false;
        }
    }
}

Now, you can run things with retries without having to conflate your task logic with your retry logic:

runWithRetries(MAX_RETRIES, () -> { /* do stuff */ });

You can tweak this as you like to accept lambdas which are called on retry, return the retry count, etc etc. But the game is to write methods like runWithRetries which capture the control flow but abstract over what behavior needs to be done -- so you only have to write your retry loop once, and then fill in the actual behavior you want wherever needed.

like image 53
Brian Goetz Avatar answered Sep 23 '22 19:09

Brian Goetz


Using Failsafe:

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

Failsafe.with(retryPolicy)
  .onRetry(r -> LOG.debug("retrying..."))
  .withFallback(e -> LOG.debug("do something else..."))
  .run(() -> someCode());

It's about as simple and expressive as you can get for your use case.

like image 27
Jonathan Avatar answered Sep 21 '22 19:09

Jonathan