0
# Retry and Circuit Breaker
1
2
Micronaut provides comprehensive resilience patterns including retry logic, circuit breakers, and bulkhead isolation to handle failures and improve application reliability.
3
4
## Capabilities
5
6
### Retry Logic
7
8
Automatically retry failed operations with configurable strategies.
9
10
```java { .api }
11
/**
12
* Retry configuration and usage
13
*/
14
@Singleton
15
public class ExternalService {
16
17
@Retryable(attempts = "3", delay = "1s")
18
public String callExternal() {
19
// Method will be retried up to 3 times with 1 second delay
20
return restClient.getData();
21
}
22
23
@Retryable(attempts = "5", delay = "2s", multiplier = "2")
24
public String callWithBackoff() {
25
// Exponential backoff: 2s, 4s, 8s, 16s
26
return restClient.getData();
27
}
28
29
@Retryable(
30
attempts = "3",
31
includes = {ConnectException.class, SocketTimeoutException.class},
32
excludes = {IllegalArgumentException.class}
33
)
34
public String callWithSpecificExceptions() {
35
// Only retry on specific exceptions
36
return restClient.getData();
37
}
38
39
@Retryable(attempts = "3", delay = "1s")
40
Single<String> reactiveRetry() {
41
// Reactive retry support
42
return Single.fromCallable(() -> restClient.getData());
43
}
44
}
45
```
46
47
### Circuit Breaker
48
49
Protect against cascading failures with circuit breaker patterns.
50
51
```java { .api }
52
/**
53
* Circuit breaker configuration
54
*/
55
@Singleton
56
public class ReliableService {
57
58
@CircuitBreaker
59
public String reliableCall() {
60
// Default circuit breaker configuration
61
return externalService.call();
62
}
63
64
@CircuitBreaker(
65
attempts = "5",
66
openTimeout = "30s",
67
resetTimeout = "60s"
68
)
69
public String configuredCircuitBreaker() {
70
// Custom circuit breaker settings
71
return externalService.call();
72
}
73
74
@CircuitBreaker(includes = {ConnectException.class})
75
@Fallback
76
public String circuitBreakerWithFallback() {
77
// Circuit breaker with fallback method
78
return externalService.call();
79
}
80
81
// Fallback method for circuitBreakerWithFallback
82
public String circuitBreakerWithFallback(CircuitOpenException ex) {
83
return "Service temporarily unavailable";
84
}
85
}
86
```
87
88
### Bulkhead Pattern
89
90
Isolate different parts of the application to prevent resource exhaustion.
91
92
```java { .api }
93
/**
94
* Bulkhead isolation
95
*/
96
@Singleton
97
public class IsolatedService {
98
99
@Bulkhead(value = "critical-operations", maxConcurrency = 10)
100
public String criticalOperation() {
101
// Limited to 10 concurrent executions
102
return performCriticalWork();
103
}
104
105
@Bulkhead(value = "background-tasks", maxConcurrency = 5, maxWaitDuration = "5s")
106
public CompletableFuture<String> backgroundTask() {
107
// Background tasks with wait timeout
108
return CompletableFuture.supplyAsync(this::performBackgroundWork);
109
}
110
}
111
```
112
113
### Timeout Protection
114
115
Add timeout protection to prevent operations from hanging indefinitely.
116
117
```java { .api }
118
/**
119
* Timeout configuration
120
*/
121
@Singleton
122
public class TimedService {
123
124
@TimedOut("5s")
125
public String timedOperation() {
126
// Operation will timeout after 5 seconds
127
return longRunningOperation();
128
}
129
130
@TimedOut("10s")
131
@Fallback
132
public String timedOperationWithFallback() {
133
// Timeout with fallback
134
return longRunningOperation();
135
}
136
137
// Fallback method for timeout
138
public String timedOperationWithFallback(TimeoutException ex) {
139
return "Operation timed out, using cached result";
140
}
141
142
@TimedOut("3s")
143
Single<String> reactiveTimeout() {
144
// Reactive timeout support
145
return Single.fromCallable(this::longRunningOperation);
146
}
147
}
148
```
149
150
### Combined Resilience Patterns
151
152
Combine multiple resilience patterns for comprehensive protection.
153
154
```java { .api }
155
/**
156
* Combined resilience patterns
157
*/
158
@Singleton
159
public class ResilientService {
160
161
@Retryable(attempts = "3", delay = "1s")
162
@CircuitBreaker(attempts = "5", openTimeout = "30s")
163
@TimedOut("10s")
164
@Fallback
165
public String resilientOperation() {
166
// Combined retry, circuit breaker, timeout, and fallback
167
return externalService.call();
168
}
169
170
// Fallback for resilientOperation
171
public String resilientOperation(Exception ex) {
172
if (ex instanceof CircuitOpenException) {
173
return "Circuit breaker is open";
174
} else if (ex instanceof TimeoutException) {
175
return "Operation timed out";
176
} else {
177
return "Operation failed after retries";
178
}
179
}
180
181
@Bulkhead("api-calls")
182
@Retryable(attempts = "2")
183
@CircuitBreaker
184
Publisher<String> resilientReactiveOperation() {
185
// Reactive resilience patterns
186
return Flowable.fromCallable(() -> externalService.call());
187
}
188
}
189
```
190
191
### Configuration
192
193
Configure resilience patterns through application properties.
194
195
```java { .api }
196
/**
197
* Resilience configuration properties
198
*/
199
@ConfigurationProperties("resilience")
200
public class ResilienceConfiguration {
201
202
@ConfigurationProperties("retry")
203
public static class RetryConfiguration {
204
private int attempts = 3;
205
private Duration delay = Duration.ofSeconds(1);
206
private double multiplier = 1.0;
207
208
// getters and setters
209
}
210
211
@ConfigurationProperties("circuit-breaker")
212
public static class CircuitBreakerConfiguration {
213
private int attempts = 5;
214
private Duration openTimeout = Duration.ofSeconds(30);
215
private Duration resetTimeout = Duration.ofMinutes(1);
216
217
// getters and setters
218
}
219
220
@ConfigurationProperties("bulkhead")
221
public static class BulkheadConfiguration {
222
private int maxConcurrency = 10;
223
private Duration maxWaitDuration = Duration.ofSeconds(5);
224
225
// getters and setters
226
}
227
}
228
```
229
230
## Types
231
232
```java { .api }
233
// Resilience annotations
234
@Target({ElementType.METHOD})
235
@Retention(RetentionPolicy.RUNTIME)
236
public @interface Retryable {
237
String attempts() default "3";
238
String delay() default "1s";
239
String multiplier() default "1.0";
240
Class<? extends Throwable>[] includes() default {};
241
Class<? extends Throwable>[] excludes() default {};
242
}
243
244
@Target({ElementType.METHOD})
245
@Retention(RetentionPolicy.RUNTIME)
246
public @interface CircuitBreaker {
247
String attempts() default "20";
248
String openTimeout() default "20s";
249
String resetTimeout() default "20s";
250
Class<? extends Throwable>[] includes() default {};
251
Class<? extends Throwable>[] excludes() default {};
252
double failureThreshold() default 0.5;
253
}
254
255
@Target({ElementType.METHOD})
256
@Retention(RetentionPolicy.RUNTIME)
257
public @interface Bulkhead {
258
String value() default "";
259
int maxConcurrency() default 10;
260
String maxWaitDuration() default "0s";
261
}
262
263
@Target({ElementType.METHOD})
264
@Retention(RetentionPolicy.RUNTIME)
265
public @interface TimedOut {
266
String value();
267
}
268
269
@Target({ElementType.METHOD})
270
@Retention(RetentionPolicy.RUNTIME)
271
public @interface Fallback {
272
}
273
274
// Exception types
275
public class CircuitOpenException extends RuntimeException {
276
public CircuitOpenException(String message);
277
public CircuitOpenException(String message, Throwable cause);
278
}
279
280
public class BulkheadRejectionException extends RuntimeException {
281
public BulkheadRejectionException(String message);
282
public BulkheadRejectionException(String message, Throwable cause);
283
}
284
285
// Circuit breaker states
286
public enum CircuitState {
287
CLOSED, OPEN, HALF_OPEN
288
}
289
290
// Retry context
291
public interface RetryContext {
292
int getCurrentAttempt();
293
int getMaxAttempts();
294
Duration getDelay();
295
Throwable getLastException();
296
}
297
```