This version is still in development and is not considered stable yet. For the latest stable version, please use Spring Cloud Commons 4.3.0!

Spring Cloud Circuit Breaker

Spring Cloud Circuit breaker provides an abstraction across different circuit breaker implementations. It provides a consistent API to use in your applications, letting you, the developer, choose the circuit breaker implementation that best fits your needs for your application.

Supported Implementations

Spring Cloud supports the following circuit-breaker implementations:

Core Concepts

To create a circuit breaker in your code, you can use the CircuitBreakerFactory API. When you include a Spring Cloud Circuit Breaker starter on your classpath, a bean that implements this API is automatically created for you. The following example shows a simple example of how to use this API:

@Service
public static class DemoControllerService {
	private RestTemplate rest;
	private CircuitBreakerFactory cbFactory;

	public DemoControllerService(RestTemplate rest, CircuitBreakerFactory cbFactory) {
		this.rest = rest;
		this.cbFactory = cbFactory;
	}

	public String slow() {
		return cbFactory.create("slow").run(() -> rest.getForObject("/slow", String.class), throwable -> "fallback");
	}

}

The CircuitBreakerFactory.create API creates an instance of a class called CircuitBreaker. The run method takes a Supplier and a Function. The Supplier is the code that you are going to wrap in a circuit breaker. The Function is the fallback that is run if the circuit breaker is tripped. The function is passed the Throwable that caused the fallback to be triggered. You can optionally exclude the fallback if you do not want to provide one.

Circuit Breakers In Reactive Code

If Project Reactor is on the class path, you can also use ReactiveCircuitBreakerFactory for your reactive code. The following example shows how to do so:

@Service
public static class DemoControllerService {
	private ReactiveCircuitBreakerFactory cbFactory;
	private WebClient webClient;


	public DemoControllerService(WebClient webClient, ReactiveCircuitBreakerFactory cbFactory) {
		this.webClient = webClient;
		this.cbFactory = cbFactory;
	}

	public Mono<String> slow() {
		return webClient.get().uri("/slow").retrieve().bodyToMono(String.class).transform(
		it -> cbFactory.create("slow").run(it, throwable -> return Mono.just("fallback")));
	}
}

The ReactiveCircuitBreakerFactory.create API creates an instance of a class called ReactiveCircuitBreaker. The run method takes a Mono or a Flux and wraps it in a circuit breaker. You can optionally profile a fallback Function, which will be called if the circuit breaker is tripped and is passed the Throwable that caused the failure.

Configuration

You can configure your circuit breakers by creating beans of type Customizer. The Customizer interface has a single method (called customize) that takes the Object to customize.

For detailed information on how to customize a given implementation see the following documentation:

Some CircuitBreaker implementations such as Resilience4JCircuitBreaker call customize method every time CircuitBreaker#run is called. It can be inefficient. In that case, you can use CircuitBreaker#once method. It is useful where calling customize many times doesn’t make sense, for example, in case of consuming Resilience4j’s events.

The following example shows the way for each io.github.resilience4j.circuitbreaker.CircuitBreaker to consume events.

Customizer.once(circuitBreaker -> {
  circuitBreaker.getEventPublisher()
    .onStateTransition(event -> log.info("{}: {}", event.getCircuitBreakerName(), event.getStateTransition()));
}, CircuitBreaker::getName)

Spring Interface Clients Support

Spring Cloud provides support for Spring Interface Clients integration through the following configurers:

  • CircuitBreakerRestClientHttpServiceGroupConfigurer

  • CircuitBreakerWebClientHttpServiceGroupConfigurer

These configurers enable CircuitBreaker support for Spring Interface Client Groups.

When fallback classes are configured using the @HttpServiceFallbackAnnotation, CircuitBreaker adapter decorators are added: - CircuitBreakerAdapterDecorator is used with RestClient - ReactiveCircuitBreakerAdapterDecorator is used with WebClient

You can disable CircuitBreaker integration for HTTP service clients by setting the appropriate property:

  • For blocking (RestClient) clients: spring.cloud.circuitbreaker.http-services.enabled=false

  • For reactive (WebClient) clients: spring.cloud.circuitbreaker.reactive-http-services.enabled=false

This prevents CircuitBreaker decorators from being applied to interface-based HTTP client groups.

Declaring Fallbacks with Annotations

Fallbacks are configured using the @HttpServiceFallback annotation on configuration classes. This annotation allows you to declare:

  • The fallback implementation class (via value)

  • The service interfaces the fallback supports (via forService, optional)

  • The group the fallback applies to (via forGroup, optional)

Multiple @HttpServiceFallback annotations can be declared on the same class using Java’s @Repeatable annotation mechanism. If no group is specified, the fallback applies to all groups that do not have an explicit per-group fallback for the given service interfaces.

Fallback classes are resolved using the following precedence:

  1. A fallback class with both matching forService and forGroup

  2. A fallback class with matching forService and no forGroup (global fallback for service)

  3. A fallback class with no forService or forGroup (default for all services in group or globally)

Example

@HttpServiceFallback(value = DefaultFallbacks.class)
@HttpServiceFallback(value = GroupAndServiceSpecificFallbacks.class, service = {BillingService.class, ShippingService.class}, group = "billing")
public class MyFallbackConfig {
    ...
}

This configuration results in:

  • DefaultFallbacks used as a global fallback for all services not explicitly handled

  • GroupAndServiceSpecificFallbacks used only for BillingService and ShippingService within the "billing" group

  • The fallback class and its methods must be public

  • Fallback methods must not be annotated with @HttpExchange annotations

How CircuitBreaker Adapters Work

The adapters wrap @HttpExchange method calls with CircuitBreaker logic. When a fallback is triggered, a proxy is created using the user-defined fallback class. The appropriate fallback method is selected by matching:

  • A method with the same name and parameter types, or

  • A method with the same name and parameter types preceded by a Throwable argument (to access the cause of failure)

Given the following interface:

@HttpExchange("/test")
public interface TestService {

    @GetExchange("/{id}")
    Person test(@PathVariable UUID id);

    @GetExchange
    String test();
}

A matching fallback class could be:

public class TestServiceFallback {

    public Person test(UUID id);

    public String test(Throwable cause);
}