Disjuntores e Isolamento por Compartimentos
Proteja chamadas a serviços dependentes com disjuntores, compartimentos e métodos de fallback do Resilience4j.
Disjuntores e Isolamento por Compartimentos é uma aula grátis de Spring Boot 4 Complete Guide no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Spring Boot 4 Complete Guide, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Spring Boot 4 Complete Guide inclui 4 aulas no total.
Partes desta aula ainda não foram traduzidas e aparecem em inglês.
Why Resilience Matters
In a distributed system, a single slow or failing downstream service can cascade into a total outage. If your service keeps calling a dead dependency, threads pile up waiting on timeouts until the whole application becomes unresponsive.
Resilience engineering is about containing failure. Two foundational patterns:
- Circuit Breaker — stop calling a failing dependency for a while, fail fast instead of waiting.
- Bulkhead — isolate resources so one saturated dependency cannot exhaust the threads or connections needed by the rest.
In Spring Boot 4 we implement these with Resilience4j, a lightweight, functional fault-tolerance library that replaced the now end-of-life Hystrix.
Adding Resilience4j
Spring Boot 4 integrates Resilience4j through the resilience4j-spring-boot3 starter (compatible with Boot 3.x/4.x) plus Spring AOP. The annotations are activated by an aspect that wraps your method calls.
You also pull in spring-boot-starter-aop and, for metrics, spring-boot-starter-actuator with Micrometer.
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot3</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>How a Circuit Breaker Works
A circuit breaker is a state machine that monitors the failure rate of calls:
- CLOSED — calls flow through normally. Failures are recorded in a sliding window.
- OPEN — once the failure rate crosses a threshold, the breaker trips. Further calls fail immediately (no downstream call) for a wait duration.
- HALF_OPEN — after the wait, a limited number of trial calls are permitted. If they succeed, it returns to CLOSED; if they fail, it returns to OPEN.
The key benefit: when a dependency is down, you fail fast instead of blocking threads on doomed calls, and you give the dependency room to recover.
Annotating a Protected Call
The @CircuitBreaker annotation wraps a method. The name ties it to a configuration instance, and fallbackMethod names a method to invoke when the call fails or the breaker is open.
The fallback must have the same signature plus a trailing Throwable (or a more specific exception) parameter.
@Service
public class PaymentClient {
private final RestClient restClient;
public PaymentClient(RestClient restClient) {
this.restClient = restClient;
}
@CircuitBreaker(name = "paymentService", fallbackMethod = "fallbackCharge")
public ChargeResult charge(ChargeRequest request) {
return restClient.post()
.uri("/charges")
.body(request)
.retrieve()
.body(ChargeResult.class);
}
private ChargeResult fallbackCharge(ChargeRequest request, Throwable t) {
return ChargeResult.deferred(request.id(), "payment temporarily unavailable");
}
}Configuring the Breaker
Circuit breaker behavior is tuned in application.yml. You define default settings and per-instances overrides keyed by the name you used in the annotation.
sliding-window-type— COUNT_BASED or TIME_BASED.failure-rate-threshold— percent of failures to open the breaker.wait-duration-in-open-state— how long to stay OPEN before HALF_OPEN.permitted-number-of-calls-in-half-open-state— trial calls allowed.slow-call-duration-threshold/slow-call-rate-threshold— treat slow calls as failures.
resilience4j:
circuitbreaker:
configs:
default:
sliding-window-type: COUNT_BASED
sliding-window-size: 20
failure-rate-threshold: 50
slow-call-duration-threshold: 2s
slow-call-rate-threshold: 80
wait-duration-in-open-state: 10s
permitted-number-of-calls-in-half-open-state: 5
automatic-transition-from-open-to-half-open-enabled: true
instances:
paymentService:
base-config: default
failure-rate-threshold: 40Modeling the State Machine in Plain Java
To internalize the logic, here is a stripped-down, framework-free model of the CLOSED to OPEN transition using a count-based window. This is conceptually what Resilience4j does for you behind the annotation.
Run it to see the breaker trip once the failure rate crosses the threshold.
public class MiniBreaker {
enum State { CLOSED, OPEN }
static State state = State.CLOSED;
static int window = 10, threshold = 50;
static boolean[] results = new boolean[window];
static int idx = 0, count = 0;
static void record(boolean failure) {
results[idx] = failure;
idx = (idx + 1) % window;
if (count < window) count++;
int fails = 0;
for (int i = 0; i < count; i++) if (results[i]) fails++;
int rate = count == 0 ? 0 : (fails * 100 / count);
if (count == window && rate >= threshold) state = State.OPEN;
}
public static void main(String[] args) {
boolean[] calls = {false,true,false,true,true,false,true,true,false,true};
for (boolean fail : calls) {
record(fail);
System.out.println((fail ? "FAIL" : "OK ") + " -> state=" + state);
}
}
}Counting Records vs Ignoring Exceptions
Not every exception should trip the breaker. A 400 Bad Request means your input was wrong, not that the dependency is unhealthy — counting it as a failure would open the breaker for valid traffic.
Use record-exceptions to list throwables that count as failures, and ignore-exceptions for those that should pass through without affecting breaker state.
resilience4j:
circuitbreaker:
instances:
paymentService:
base-config: default
record-exceptions:
- java.io.IOException
- java.util.concurrent.TimeoutException
- org.springframework.web.client.HttpServerErrorException
ignore-exceptions:
- com.example.payments.InvalidCardException
- org.springframework.web.client.HttpClientErrorException$BadRequestBulkhead Isolation
The bulkhead pattern (named after a ship's watertight compartments) limits how many concurrent calls a dependency can consume, so one slow service cannot drain the entire thread pool.
Resilience4j offers two flavors:
- SemaphoreBulkhead — caps concurrent calls on the caller's thread. Lightweight, no extra threads.
- ThreadPoolBulkhead — runs calls on a dedicated, bounded thread pool with a queue. Provides true isolation and only works with asynchronous returns (
CompletableFuture).
If the bulkhead is full, the call is rejected with BulkheadFullException, which your fallback can handle.
Applying a Bulkhead
The @Bulkhead annotation limits concurrency. With type = THREADPOOL the method must return a CompletableFuture and runs on the bulkhead's own pool. You can stack it with @CircuitBreaker — the annotations compose.
@Service
public class InventoryClient {
private final RestClient restClient;
public InventoryClient(RestClient restClient) {
this.restClient = restClient;
}
@CircuitBreaker(name = "inventory", fallbackMethod = "fallbackStock")
@Bulkhead(name = "inventory", type = Bulkhead.Type.THREADPOOL)
public CompletableFuture<StockLevel> getStock(String sku) {
return CompletableFuture.completedFuture(
restClient.get().uri("/stock/{sku}", sku)
.retrieve().body(StockLevel.class));
}
private CompletableFuture<StockLevel> fallbackStock(String sku, Throwable t) {
return CompletableFuture.completedFuture(StockLevel.unknown(sku));
}
}Configuring Bulkheads
Semaphore and thread-pool bulkheads have separate config sections.
bulkhead(semaphore):max-concurrent-callsandmax-wait-duration(how long a call waits for a permit before being rejected).thread-pool-bulkhead:max-thread-pool-size,core-thread-pool-size, andqueue-capacity.
Right-size these to the dependency's real capacity: a bulkhead larger than the downstream can handle defeats the purpose.
resilience4j:
bulkhead:
instances:
paymentService:
max-concurrent-calls: 25
max-wait-duration: 50ms
thread-pool-bulkhead:
instances:
inventory:
core-thread-pool-size: 8
max-thread-pool-size: 16
queue-capacity: 20Ordering, Fallbacks, and Observability
When multiple Resilience4j annotations decorate one method, they apply in a fixed aspect order (highest precedence first): Bulkhead → TimeLimiter → RateLimiter → CircuitBreaker → Retry. So Retry wraps the circuit breaker — a retried call that still fails counts toward the breaker.
Fallback design rules:
- Keep fallbacks fast and side-effect-free; never call the failing dependency again.
- Return degraded-but-valid data (cached value, default, queued-for-later).
- Inspect the
Throwableto distinguishCallNotPermittedException(breaker open) fromBulkheadFullException(overloaded).
Actuator exposes state and metrics at /actuator/circuitbreakers and via Micrometer (resilience4j_circuitbreaker_state), so you can alert on OPEN breakers.
private ChargeResult fallbackCharge(ChargeRequest request, CallNotPermittedException ex) {
return ChargeResult.deferred(request.id(), "breaker open");
}
private ChargeResult fallbackCharge(ChargeRequest request, BulkheadFullException ex) {
return ChargeResult.rejected(request.id(), "system busy");
}
private ChargeResult fallbackCharge(ChargeRequest request, Throwable t) {
return ChargeResult.deferred(request.id(), "payment unavailable");
}Quick Check
Test your understanding of bulkhead isolation.
Recap
You learned how to protect downstream calls in Spring Boot 4 with Resilience4j:
- Circuit breakers fail fast via the CLOSED → OPEN → HALF_OPEN state machine, tuned with sliding-window size, failure-rate and slow-call thresholds, and wait duration.
- Use
record-exceptions/ignore-exceptionsso client errors (4xx) don't trip the breaker. - Bulkheads cap concurrency — SemaphoreBulkhead on the caller thread, ThreadPoolBulkhead for true isolation with
CompletableFuture. - Fallback methods share the signature plus a trailing
Throwable; return degraded-but-valid data and never re-call the failing dependency. - Annotation order is Bulkhead → TimeLimiter → RateLimiter → CircuitBreaker → Retry; observe state through Actuator and Micrometer.
Together these patterns keep one failing dependency from taking down your whole service.
Perguntas Frequentes
A aula “Disjuntores e Isolamento por Compartimentos” é grátis?
Sim — o texto completo de “Disjuntores e Isolamento por Compartimentos” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Spring Boot 4 Complete Guide, atualize para CoddyKit PRO. O curso de Spring Boot 4 Complete Guide inclui 4 aulas no total.
O que vou aprender em “Disjuntores e Isolamento por Compartimentos”?
Proteja chamadas a serviços dependentes com disjuntores, compartimentos e métodos de fallback do Resilience4j. Você pratica Spring Boot 4 Complete Guide com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar Spring Boot 4 Complete Guide?
Nenhuma experiência prévia é necessária. Spring Boot 4 Complete Guide no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.
Quanto tempo leva a aula “Disjuntores e Isolamento por Compartimentos”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de Spring Boot 4 Complete Guide?
Sim. Cada aula de Spring Boot 4 Complete Guide inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Propagação de Contexto e Instrumentação de Intervalos
- Disjuntores e Isolamento por Compartimentos
- Limitação de Taxa, Novas Tentativas e Limitadores de Tempo
- Correlação de Registros, Métricas e Rastreamentos