Spring Retry - Quick Reference
Full Reference: See advanced.md for RetryTemplate patterns, custom retry policies, retry listeners, stateful retry, async retry, and testing.
Deep Knowledge: Use mcp__documentation__fetch_docs with technology: spring-retry for comprehensive documentation.
Dependencies
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
Enable Retry
@SpringBootApplication
@EnableRetry
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Retryable Annotation
Basic Usage
@Retryable(maxAttempts = 3)
public String callExternalApi(String endpoint) {
return restClient.get(endpoint);
}
With Specific Exceptions
@Retryable(
retryFor = {ServiceUnavailableException.class, TimeoutException.class},
noRetryFor = {PaymentDeclinedException.class},
maxAttempts = 5
)
public PaymentResult processPayment(PaymentRequest request) {
return paymentGateway.charge(request);
}
With Backoff
@Retryable(
maxAttempts = 4,
backoff = @Backoff(
delay = 1000, // Initial delay: 1 second
multiplier = 2, // Exponential: 1s, 2s, 4s
maxDelay = 10000 // Max delay: 10 seconds
)
)
public void sendNotification(Notification notification) {
notificationClient.send(notification);
}
@Recover
public void recoverNotification(Exception e, Notification notification) {
log.error("Failed to send notification after retries: {}", notification.getId());
deadLetterQueue.add(notification);
}
@Recover Method
@Service
public class UserService {
@Retryable(retryFor = ServiceException.class, maxAttempts = 3)
public User getUser(Long id) {
return userClient.findById(id);
}
// Must have same return type
// First parameter can be the exception
@Recover
public User recoverGetUser(ServiceException e, Long id) {
log.warn("Falling back to cached user for id: {}", id);
return userCache.get(id);
}
// Multiple recover methods for different exceptions
@Recover
public User recoverGetUserTimeout(TimeoutException e, Long id) {
return User.unknown(id);
}
}
Best Practices
| Do |
Don't |
| Use exponential backoff |
Fixed rapid retries |
| Set max attempts limit |
Retry indefinitely |
| Handle non-retryable exceptions |
Retry business errors |
| Log retry attempts |
Silent retries |
| Implement recovery fallback |
Let retries fail silently |
When NOT to Use This Skill
- Circuit breaker - Use
spring-cloud-circuitbreaker or Resilience4j
- Message retry - Use Kafka retry topics or DLT
- Non-idempotent operations - Ensure idempotency first
- Business errors - Only retry transient failures
Anti-Patterns
| Anti-Pattern |
Problem |
Solution |
| Retry indefinitely |
Hangs forever |
Set max attempts |
| Fixed rapid retry |
Overwhelms service |
Use exponential backoff |
| Retrying business errors |
Wastes resources |
Use noRetryFor |
| No recovery method |
Silent failures |
Implement @Recover |
Quick Troubleshooting
| Problem |
Diagnostic |
Fix |
| Retry not happening |
Check @EnableRetry |
Add to config class |
| @Recover not called |
Check method signature |
Match return type and params |
| Too many retries |
Check maxAttempts |
Reduce or add timeout |
| Backoff not working |
Check annotation |
Verify @Backoff config |
Production Checklist
Reference Documentation