0
# Circuit Breakers
1
2
Circuit breakers provide resilience patterns for handling service failures and preventing cascading failures in distributed systems. Spring Cloud Commons provides abstractions for both synchronous and reactive circuit breaker implementations.
3
4
## Capabilities
5
6
### Enable Circuit Breaker
7
8
Enables circuit breaker functionality in your Spring Boot application.
9
10
```java { .api }
11
/**
12
* Enables circuit breaker functionality
13
*/
14
@EnableCircuitBreaker
15
public @interface EnableCircuitBreaker {}
16
```
17
18
**Usage Example:**
19
20
```java
21
@SpringBootApplication
22
@EnableCircuitBreaker
23
public class MyApplication {
24
public static void main(String[] args) {
25
SpringApplication.run(MyApplication.class, args);
26
}
27
}
28
```
29
30
### Circuit Breaker Interface
31
32
Main interface for synchronous circuit breaker operations.
33
34
```java { .api }
35
/**
36
* Main interface for synchronous circuit breaker operations
37
*/
38
public interface CircuitBreaker {
39
/**
40
* Execute a supplier within the circuit breaker
41
* @param toRun The supplier to execute
42
* @return The result from the supplier
43
*/
44
<T> T run(Supplier<T> toRun);
45
46
/**
47
* Execute a supplier within the circuit breaker with fallback
48
* @param toRun The supplier to execute
49
* @param fallback The fallback function to execute if the supplier fails
50
* @return The result from the supplier or fallback
51
*/
52
<T> T run(Supplier<T> toRun, Function<Throwable, T> fallback);
53
}
54
```
55
56
**Usage Examples:**
57
58
```java
59
@Service
60
public class UserService {
61
62
@Autowired
63
private CircuitBreakerFactory circuitBreakerFactory;
64
65
private CircuitBreaker circuitBreaker;
66
67
@PostConstruct
68
public void init() {
69
this.circuitBreaker = circuitBreakerFactory.create("user-service");
70
}
71
72
public String getUser(String userId) {
73
return circuitBreaker.run(
74
() -> callUserService(userId),
75
throwable -> "Default User"
76
);
77
}
78
79
public String getUserWithNoFallback(String userId) {
80
return circuitBreaker.run(() -> callUserService(userId));
81
}
82
83
private String callUserService(String userId) {
84
// Make HTTP call to user service
85
RestTemplate restTemplate = new RestTemplate();
86
return restTemplate.getForObject("http://user-service/users/" + userId, String.class);
87
}
88
}
89
```
90
91
### Reactive Circuit Breaker
92
93
Reactive interface for circuit breaker operations using Project Reactor.
94
95
```java { .api }
96
/**
97
* Reactive interface for circuit breaker operations
98
*/
99
public interface ReactiveCircuitBreaker {
100
/**
101
* Execute a Mono within the circuit breaker
102
* @param toRun The Mono to execute
103
* @return The Mono result wrapped in circuit breaker logic
104
*/
105
<T> Mono<T> run(Mono<T> toRun);
106
107
/**
108
* Execute a Mono within the circuit breaker with fallback
109
* @param toRun The Mono to execute
110
* @param fallback The fallback function to execute if the Mono fails
111
* @return The Mono result or fallback wrapped in circuit breaker logic
112
*/
113
<T> Mono<T> run(Mono<T> toRun, Function<Throwable, Mono<T>> fallback);
114
115
/**
116
* Execute a Flux within the circuit breaker
117
* @param toRun The Flux to execute
118
* @return The Flux result wrapped in circuit breaker logic
119
*/
120
<T> Flux<T> run(Flux<T> toRun);
121
122
/**
123
* Execute a Flux within the circuit breaker with fallback
124
* @param toRun The Flux to execute
125
* @param fallback The fallback function to execute if the Flux fails
126
* @return The Flux result or fallback wrapped in circuit breaker logic
127
*/
128
<T> Flux<T> run(Flux<T> toRun, Function<Throwable, Flux<T>> fallback);
129
}
130
```
131
132
**Usage Examples:**
133
134
```java
135
@Service
136
public class ReactiveUserService {
137
138
@Autowired
139
private ReactiveCircuitBreakerFactory reactiveCircuitBreakerFactory;
140
141
private ReactiveCircuitBreaker circuitBreaker;
142
143
@PostConstruct
144
public void init() {
145
this.circuitBreaker = reactiveCircuitBreakerFactory.create("user-service");
146
}
147
148
public Mono<String> getUser(String userId) {
149
return circuitBreaker.run(
150
callUserServiceReactively(userId),
151
throwable -> Mono.just("Default User")
152
);
153
}
154
155
public Flux<String> getAllUsers() {
156
return circuitBreaker.run(
157
callAllUsersReactively(),
158
throwable -> Flux.just("Default User 1", "Default User 2")
159
);
160
}
161
162
private Mono<String> callUserServiceReactively(String userId) {
163
WebClient webClient = WebClient.create();
164
return webClient.get()
165
.uri("http://user-service/users/{id}", userId)
166
.retrieve()
167
.bodyToMono(String.class);
168
}
169
170
private Flux<String> callAllUsersReactively() {
171
WebClient webClient = WebClient.create();
172
return webClient.get()
173
.uri("http://user-service/users")
174
.retrieve()
175
.bodyToFlux(String.class);
176
}
177
}
178
```
179
180
### Circuit Breaker Factory
181
182
Abstract factory for creating circuit breaker instances.
183
184
```java { .api }
185
/**
186
* Abstract factory for creating circuit breaker instances
187
*/
188
public abstract class CircuitBreakerFactory<CONF, CONFB> {
189
/**
190
* Create a circuit breaker with the given ID
191
* @param id The circuit breaker ID
192
* @return A new CircuitBreaker instance
193
*/
194
public abstract CircuitBreaker create(String id);
195
196
/**
197
* Create a circuit breaker with the given ID and group
198
* @param id The circuit breaker ID
199
* @param groupName The circuit breaker group name
200
* @return A new CircuitBreaker instance
201
*/
202
public CircuitBreaker create(String id, String groupName) {
203
return create(id);
204
}
205
206
/**
207
* Configure the factory
208
* @param consumer Configuration consumer
209
*/
210
public abstract void configure(Consumer<CONFB> consumer);
211
212
/**
213
* Configure a specific circuit breaker
214
* @param id The circuit breaker ID
215
* @param consumer Configuration consumer
216
*/
217
public abstract void configure(String id, Consumer<CONFB> consumer);
218
219
/**
220
* Configure a group of circuit breakers
221
* @param groupName The group name
222
* @param consumer Configuration consumer
223
*/
224
public void configureGroup(String groupName, Consumer<CONFB> consumer) {
225
// Default implementation - override as needed
226
}
227
}
228
229
/**
230
* Abstract factory for reactive circuit breakers
231
*/
232
public abstract class ReactiveCircuitBreakerFactory<CONF, CONFB> {
233
/**
234
* Create a reactive circuit breaker with the given ID
235
* @param id The circuit breaker ID
236
* @return A new ReactiveCircuitBreaker instance
237
*/
238
public abstract ReactiveCircuitBreaker create(String id);
239
240
/**
241
* Create a reactive circuit breaker with the given ID and group
242
* @param id The circuit breaker ID
243
* @param groupName The circuit breaker group name
244
* @return A new ReactiveCircuitBreaker instance
245
*/
246
public ReactiveCircuitBreaker create(String id, String groupName) {
247
return create(id);
248
}
249
250
/**
251
* Configure the factory
252
* @param consumer Configuration consumer
253
*/
254
public abstract void configure(Consumer<CONFB> consumer);
255
256
/**
257
* Configure a specific reactive circuit breaker
258
* @param id The circuit breaker ID
259
* @param consumer Configuration consumer
260
*/
261
public abstract void configure(String id, Consumer<CONFB> consumer);
262
263
/**
264
* Configure a group of reactive circuit breakers
265
* @param groupName The group name
266
* @param consumer Configuration consumer
267
*/
268
public void configureGroup(String groupName, Consumer<CONFB> consumer) {
269
// Default implementation - override as needed
270
}
271
}
272
273
/**
274
* Base implementation of circuit breaker factory
275
*/
276
public abstract class AbstractCircuitBreakerFactory<CONF, CONFB> extends CircuitBreakerFactory<CONF, CONFB> {
277
protected Map<String, CONF> configurations = new ConcurrentHashMap<>();
278
protected Map<String, CONF> groupConfigurations = new ConcurrentHashMap<>();
279
280
/**
281
* Get configuration for a circuit breaker
282
* @param id The circuit breaker ID
283
* @return The configuration
284
*/
285
protected CONF getConfiguration(String id) {
286
return configurations.get(id);
287
}
288
289
/**
290
* Get group configuration
291
* @param groupName The group name
292
* @return The group configuration
293
*/
294
protected CONF getGroupConfiguration(String groupName) {
295
return groupConfigurations.get(groupName);
296
}
297
}
298
```
299
300
### Configuration Builder
301
302
Interface for building circuit breaker configurations.
303
304
```java { .api }
305
/**
306
* Interface for building circuit breaker configurations
307
*/
308
public interface ConfigBuilder<CONF> {
309
/**
310
* Build the configuration
311
* @return The built configuration
312
*/
313
CONF build();
314
}
315
```
316
317
### Customization Support
318
319
Interface for customizing circuit breaker components.
320
321
```java { .api }
322
/**
323
* Interface for customizing components
324
*/
325
public interface Customizer<TOCUSTOMIZE> {
326
/**
327
* Customize the component
328
* @param t The component to customize
329
*/
330
void customize(TOCUSTOMIZE t);
331
}
332
```
333
334
### Exception Handling
335
336
Exception thrown when no fallback is available.
337
338
```java { .api }
339
/**
340
* Exception thrown when no fallback is available
341
*/
342
public class NoFallbackAvailableException extends RuntimeException {
343
/**
344
* Create exception with message
345
* @param message The error message
346
*/
347
public NoFallbackAvailableException(String message);
348
349
/**
350
* Create exception with message and cause
351
* @param message The error message
352
* @param cause The underlying cause
353
*/
354
public NoFallbackAvailableException(String message, Throwable cause);
355
}
356
```
357
358
## Configuration Examples
359
360
**Basic Circuit Breaker Configuration:**
361
362
```java
363
@Configuration
364
public class CircuitBreakerConfig {
365
366
@Bean
367
public Customizer<ReactiveResilience4JCircuitBreakerFactory> defaultCustomizer() {
368
return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
369
.circuitBreakerConfig(CircuitBreakerConfig.ofDefaults())
370
.timeLimiterConfig(TimeLimiterConfig.custom()
371
.timeoutDuration(Duration.ofSeconds(4))
372
.build())
373
.build());
374
}
375
376
@Bean
377
public Customizer<ReactiveResilience4JCircuitBreakerFactory> specificCustomizer() {
378
return factory -> factory.configure(builder -> builder
379
.circuitBreakerConfig(CircuitBreakerConfig.custom()
380
.failureRateThreshold(50)
381
.waitDurationInOpenState(Duration.ofMillis(1000))
382
.slidingWindowSize(2)
383
.build())
384
.timeLimiterConfig(TimeLimiterConfig.custom()
385
.timeoutDuration(Duration.ofSeconds(2))
386
.build()), "user-service", "order-service");
387
}
388
}
389
```
390
391
**Circuit Breaker with Custom Fallback:**
392
393
```java
394
@Service
395
public class OrderService {
396
397
@Autowired
398
private CircuitBreakerFactory circuitBreakerFactory;
399
400
private CircuitBreaker circuitBreaker;
401
402
@PostConstruct
403
public void init() {
404
this.circuitBreaker = circuitBreakerFactory.create("order-service");
405
}
406
407
public Order getOrder(String orderId) {
408
return circuitBreaker.run(
409
() -> fetchOrderFromService(orderId),
410
throwable -> {
411
log.error("Failed to fetch order, using fallback", throwable);
412
return Order.builder()
413
.id(orderId)
414
.status("UNKNOWN")
415
.build();
416
}
417
);
418
}
419
420
private Order fetchOrderFromService(String orderId) {
421
// Simulate service call that might fail
422
if (Math.random() > 0.5) {
423
throw new RuntimeException("Service unavailable");
424
}
425
return new Order(orderId, "CONFIRMED");
426
}
427
}
428
```
429
430
**Reactive Circuit Breaker with WebClient:**
431
432
```java
433
@Service
434
public class ReactiveOrderService {
435
436
@Autowired
437
private ReactiveCircuitBreakerFactory reactiveCircuitBreakerFactory;
438
439
private ReactiveCircuitBreaker circuitBreaker;
440
private WebClient webClient;
441
442
@PostConstruct
443
public void init() {
444
this.circuitBreaker = reactiveCircuitBreakerFactory.create("order-service");
445
this.webClient = WebClient.create("http://order-service");
446
}
447
448
public Mono<Order> getOrder(String orderId) {
449
return circuitBreaker.run(
450
webClient.get()
451
.uri("/orders/{id}", orderId)
452
.retrieve()
453
.bodyToMono(Order.class),
454
throwable -> Mono.just(Order.builder()
455
.id(orderId)
456
.status("FALLBACK")
457
.build())
458
);
459
}
460
461
public Flux<Order> getAllOrders() {
462
return circuitBreaker.run(
463
webClient.get()
464
.uri("/orders")
465
.retrieve()
466
.bodyToFlux(Order.class),
467
throwable -> Flux.just(
468
Order.builder().id("1").status("FALLBACK").build(),
469
Order.builder().id("2").status("FALLBACK").build()
470
)
471
);
472
}
473
}
474
```