Implement Retry Logic in Java
This post will discuss how to implement retry logic in Java.
1. Simple for-loop with try-catch
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).
The following program demonstrates this. Note that the code is enclosed within a try-catch and if an exception happens inside the try block, the control goes to the catch block. After handling the exception, the system runs the code again after 1 second. After all retries are exhausted and the last re-try fails, the system throws an exception.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
import java.util.Random; public class Main { private static final int MAX_RETRIES = 5; public static void main(String[] args) throws InterruptedException { for (int i = 0; i <= MAX_RETRIES; i++) { try { // generate 0 or 1 with equal probability int zeroOrOne = new Random().nextInt(2); System.out.println("Random number is.. " + zeroOrOne); // 50% probability of getting java.lang.ArithmeticException: / by zero int rand = 1 / zeroOrOne; // don't retry on success break; } catch (Exception ex) { // handle exception System.out.println(ex.getMessage()); // log the exception // sleep for 1 seconds before retrying (Optional) Thread.sleep(1000); // throw exception if the last re-try fails if (i == MAX_RETRIES) { throw ex; } } } } } |
Output (will vary):
Random number is.. 0
/ by zero
Random number is.. 0
/ by zero
Random number is.. 1
2. Using Interface
We can easily tweak the above logic to isolate the task logic with the retry logic using an interface. The following code demonstrates this.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
import java.util.Random; interface Task { void run(); void handleException(Exception ex); } public class Main { private static final int MAX_RETRIES = 5; public static void withMaxRetries(Task task) { for (int i = 0; i <= MAX_RETRIES; i++) { try { task.run(); break; // don't retry on success } catch (Exception ex) { task.handleException(ex); // throw exception if the last re-try fails if (i == MAX_RETRIES) { throw ex; } } } } public static void main(String[] args) { withMaxRetries(new Task() { @Override public void run() { // generate 0 or 1 with equal probability int zeroOrOne = new Random().nextInt(2); System.out.println("Random number is.. " + zeroOrOne); // 50% probability of getting java.lang.ArithmeticException: / by zero int rand = 1 / zeroOrOne; } @Override public void handleException(Exception ex) { System.out.println(ex.getMessage()); // log the exception try { // sleep for 1 seconds before retrying (Optional) Thread.sleep(1000); } catch (InterruptedException e) { System.out.println(e.getMessage()); // log the exception } } }); } } |
Output (will vary):
Random number is.. 0
/ by zero
Random number is.. 0
/ by zero
Random number is.. 0
/ by zero
Random number is.. 1
3. Third-party libraries
If your project is up for using third-party libraries, we recommend using the following libraries that has strong support for retry logic in Java.
1. Failsafe
Failsafe is a lightweight, zero-dependency library for handling failures in Java 8+. Failsafe works by wrapping executable logic with one or more resilience policies, which can be combined and composed as needed.
To start, create a retry policy that defines which failures should be handled and when retries should be performed:
|
1 2 3 4 5 |
RetryPolicy<Object> retryPolicy = RetryPolicy.builder() .handle(ConnectException.class) .withDelay(Duration.ofSeconds(1)) .withMaxRetries(3) .build(); |
Then you can execute a Runnable or Supplier with retries:
|
1 2 3 4 5 |
// Run with retries Failsafe.with(retryPolicy).run(() -> connect()); // Get with retries Connection connection = Failsafe.with(retryPolicy).get(() -> connect()); |
Read more – Failsafe Documentation
2. Guava-retrying
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.
The minimal sample of some of the functionality would look like:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
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.
Read more – Guava-retrying Documentation
That’s all about implemeting retry logic in Java.
Thanks for reading.
To share your code in the comments, please use our online compiler that supports C, C++, Java, Python, JavaScript, C#, PHP, and many more popular programming languages.
Like us? Refer us to your friends and support our growth. Happy coding :)