Backend Development 16 min read

Mastering Retry Strategies in Java: 8 Practical Implementations

This article explains why retry mechanisms are essential for unreliable network calls in distributed systems and presents eight concrete Java implementations—including loop, recursion, HttpClient built‑in, Spring Retry, Resilience4j, custom utilities, asynchronous thread‑pool, and message‑queue approaches—plus best‑practice guidelines to avoid common pitfalls.

macrozheng
macrozheng
macrozheng
Mastering Retry Strategies in Java: 8 Practical Implementations

Retry Mechanism Implementations

1. Loop Retry

The simplest method wraps the request in a

for

loop, retrying up to a configured maximum and sleeping between attempts.

<code>int retryTimes = 3;
for (int i = 0; i < retryTimes; i++) {
    try {
        // request code
        break;
    } catch (Exception e) {
        // handle exception
        Thread.sleep(1000); // delay 1s before next try
    }
}
</code>

2. Recursive Retry

A recursive method calls itself when an exception occurs, decreasing the remaining retry count each time.

<code>public void requestWithRetry(int retryTimes) {
    if (retryTimes <= 0) return;
    try {
        // request code
    } catch (Exception e) {
        Thread.sleep(1000);
        requestWithRetry(retryTimes - 1);
    }
}
</code>

3. Built‑in HttpClient Retry

Apache HttpClient provides built‑in retry handlers. For version 4.5+, use

HttpClients.custom().setRetryHandler(...)

; for 5.x, use

setRetryStrategy(...)

.

<code>CloseableHttpClient httpClient = HttpClients.custom()
    .setRetryHandler(new DefaultHttpRequestRetryHandler(3, true))
    .build();
</code>

4. Spring Retry Library

Spring Retry offers

RetryTemplate

for programmatic retries and

@Retryable

annotations for declarative retries.

<code>RetryTemplate retryTemplate = new RetryTemplate();
RetryPolicy retryPolicy = new SimpleRetryPolicy(3);
retryTemplate.setRetryPolicy(retryPolicy);
FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
backOffPolicy.setBackOffPeriod(1000);
retryTemplate.setBackOffPolicy(backOffPolicy);

retryTemplate.execute(context -> {
    // request code
    return null;
});
</code>

Or with annotations:

<code>@Retryable(value = Exception.class, maxAttempts = 3)
public void request() {
    // request code
}
</code>

5. Resilience4j

Resilience4j provides a lightweight retry module configurable via

RetryConfig

and usable through decorators or annotations.

<code>RetryRegistry retryRegistry = RetryRegistry.ofDefaults();
RetryConfig config = RetryConfig.custom()
    .maxAttempts(3)
    .waitDuration(Duration.ofMillis(1000))
    .retryOnResult(r -> r.getStatus() == 500)
    .retryOnException(e -> e instanceof WebServiceException)
    .build();
Retry retry = retryRegistry.retry("myRetry", config);

CheckedFunction0<String> retryableSupplier = Retry.decorateCheckedSupplier(
    retry, () -> "result");
</code>

6. Custom Retry Utility

A lightweight custom utility can be built with a

Callback

abstract class returning a

RetryResult

. The executor loops until the callback signals success or the maximum attempts are reached.

<code>public abstract class Callback {
    public abstract RetryResult doProcess();
}

public class RetryResult {
    private Boolean isRetry;
    private Object obj;
    // constructors, getters omitted
    public static RetryResult ofResult(Boolean isRetry, Object obj) {
        return new RetryResult(isRetry, obj);
    }
    public static RetryResult ofResult(Boolean isRetry) {
        return new RetryResult(isRetry, null);
    }
}

public class RetryExecutor {
    public static Object execute(int retryCount, Callback callback) {
        for (int i = 0; i < retryCount; i++) {
            RetryResult result = callback.doProcess();
            if (result.isRetry()) continue;
            return result.getObj();
        }
        return null;
    }
}
</code>

7. Asynchronous Retry with ThreadPoolExecutor

Using a thread pool, the request is submitted as a

Callable

. If the task fails, the loop retries after a delay.

<code>int maxRetryTimes = 3;
int currentRetryTimes = 0;
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    10, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
Callable<String> task = () -> {
    // request code
    return "result";
};
Future<String> future;
while (currentRetryTimes < maxRetryTimes) {
    try {
        future = executor.submit(task);
        String result = future.get();
        break;
    } catch (Exception e) {
        currentRetryTimes++;
        Thread.sleep(1000);
    }
}
</code>

8. Message‑Queue Retry (RocketMQ)

When a request fails, the message can be re‑published to RocketMQ for later processing, ensuring reliability even if the service is temporarily unavailable.

<code>@Component
@RocketMQMessageListener(topic = "myTopic", consumerGroup = "myConsumerGroup")
public class MyConsumer implements RocketMQListener<String> {
    @Override
    public void onMessage(String message) {
        try {
            // request code
        } catch (Exception e) {
            DefaultMQProducer producer = new DefaultMQProducer("myProducerGroup");
            producer.setNamesrvAddr("127.0.0.1:9876");
            try {
                producer.start();
                Message msg = new Message("myTopic", "myTag", message.getBytes());
                producer.send(msg);
            } finally {
                producer.shutdown();
            }
        }
    }
}
</code>

Best Practices and Cautions

Set reasonable retry counts and intervals to avoid overwhelming the target service.

Ensure the operation is idempotent; otherwise, repeated attempts may cause inconsistent state.

Handle concurrency carefully—use locks or distributed locks when multiple threads may retry the same request.

Distinguish retry‑able exceptions (e.g., timeouts, connection errors) from non‑retry‑able ones (e.g., validation errors).

Avoid infinite loops; always enforce a maximum number of attempts and back‑off strategy.

JavaconcurrencySpringretryHttpClientResilience4j
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.