Spring Boot @Retryable Tutorial: Automatic Retry Made Easy with Full Example

2 min read

Spring Boot @Retryable Tutorial: Automatic Retry Made Easy with Full Example

In modern applications, transient errors such as network glitches or temporary service unavailability are inevitable. Instead of failing immediately, it’s often desirable to retry failed operations a few times before giving up. Spring Boot simplifies this with the @Retryable annotation from the Spring Retry library.

In this article, we’ll walk through:

  • What @Retryable is
  • How to enable and configure it in Spring Boot
  • A real-world example using a simulated service failure
  • Best practices for using retries in production systems

What is @Retryable?

@Retryable is an annotation from the Spring Retry project that allows you to automatically retry a method upon encountering specific exceptions.

Use Cases for @Retryable

  • Retrying failed HTTP calls to an external API
  • Retrying database or message queue operations
  • Handling transient cloud infrastructure errors (e.g., AWS, Azure, GCP)

Step-by-Step Guide to Using @Retryable in Spring Boot

1. Add Spring Retry to Your Project

If you’re using Maven, add the following dependency:

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

If you’re using Gradle:

implementation 'org.springframework.retry:spring-retry'
implementation 'org.springframework.boot:spring-boot-starter-aop'

spring-boot-starter-aop is required because Spring Retry uses proxies to intercept method calls.


2. Enable Retry Support

Add the @EnableRetry annotation to your main application class or a configuration class:

@SpringBootApplication
@EnableRetry
public class RetryableExampleApplication {
    public static void main(String[] args) {
        SpringApplication.run(RetryableExampleApplication.class, args);
    }
}

3. Create a Service with Retry Logic

Here’s a simple service that fails randomly to simulate an unstable remote call:

@Service
public class UnstableService {

    private int attempt = 1;

    @Retryable(
        value = { RemoteServiceException.class },
        maxAttempts = 4,
        backoff = @Backoff(delay = 2000, multiplier = 2)
    )
    public void callRemoteService() {
        System.out.println("Attempt #" + attempt + " to call remote service");
        if (attempt++ < 3) {
            throw new RemoteServiceException("Temporary failure");
        }
        System.out.println("Success on attempt #" + attempt);
    }

    @Recover
    public void recover(RemoteServiceException e) {
        System.out.println("All retries failed: " + e.getMessage());
    }
}

4. Custom Exception

Define a custom exception class to simulate transient errors:

public class RemoteServiceException extends RuntimeException {
    public RemoteServiceException(String message) {
        super(message);
    }
}

5. Call the Service

You can call the service from a REST controller or from CommandLineRunner during startup:

@Component
public class RetryRunner implements CommandLineRunner {

    @Autowired
    private UnstableService unstableService;

    @Override
    public void run(String... args) {
        unstableService.callRemoteService();
    }
}

Output

You’ll see console output similar to this:

Attempt #1 to call remote service
Attempt #2 to call remote service
Attempt #3 to call remote service
Success on attempt #4

Or if all retries fail:

Attempt #1 to call remote service
Attempt #2 to call remote service
Attempt #3 to call remote service
Attempt #4 to call remote service
All retries failed: Temporary failure

Explanation of @Retryable Parameters

  • value: Exception types to trigger a retry
  • maxAttempts: Maximum number of attempts (including the first one)
  • backoff: Delay between attempts
    • delay: Initial wait time in milliseconds
    • multiplier: How much to multiply the delay on each retry (exponential backoff)

Best Practices

  • Use retries only for transient errors (e.g., timeouts, temporary 5xx errors)
  • Avoid retrying non-idempotent operations (e.g., creating a record)
  • Always implement a @Recover method to handle final failure gracefully
  • Log attempts and outcomes for observability

Conclusion

The @Retryable annotation in Spring Boot is a powerful and easy way to make your services more resilient to temporary failures. With minimal configuration, you can add retry logic to any method and control the behavior using parameters like maxAttempts and backoff.

By adopting Spring Retry, you improve the fault tolerance of your system and enhance user experience in the face of temporary issues.

Leave a Reply

Your email address will not be published. Required fields are marked *