O desenvolvimento de software distribuído traz consigo um problema quase inevitável: quanto mais serviços interdependentes você tem, maior a superfície de falha. Um único serviço instável pode desencadear uma reação em cadeia — o que a literatura chama de cascading failure — derrubando partes do sistema que, em teoria, não teriam nada a ver com o problema original. O Circuit Breaker é um padrão de projeto criado exatamente para quebrar esse ciclo.
A analogia com a elétrica é precisa: assim como um disjuntor corta a corrente antes que um curto-circuito queime toda a instalação, o Circuit Breaker de software interrompe chamadas a um serviço que está falhando, evitando que o problema se alastre. A ideia foi popularizada por Martin Fowler em 2014 e ganhou tração especialmente com a adoção em larga escala de microsserviços.
Os três estados do circuito
O comportamento do padrão gira em torno de uma máquina de estados simples, com três posições:
Fechado (Closed) é o estado normal. As requisições passam livremente ao serviço de destino. O circuito monitora a taxa de erros em uma janela de tempo configurável — se ela ficar abaixo do limiar definido, nada muda.
Aberto (Open) é ativado quando a taxa de falhas ultrapassa o limiar. A partir daqui, nenhuma chamada chega ao serviço problemático: o circuito retorna imediatamente um erro (ou executa um fallback), poupando recursos e evitando que um serviço lento ou indisponível segure threads em espera. Após um período de espera configurado, o circuito passa automaticamente para o terceiro estado.
Meio-aberto (Half-Open) é a fase de sondagem. O circuito deixa passar um número limitado de requisições de teste para verificar se o serviço se recuperou. Se essas chamadas tiverem sucesso, o circuito fecha novamente; se falharem, abre outra vez e o ciclo recomeça.
Essa transição automática é o que diferencia o Circuit Breaker de um simples retry com backoff: ele aprende com o comportamento do serviço e adapta sua resposta ao longo do tempo.
Implementando com Resilience4j no Spring Boot
O Hystrix da Netflix, que por muito tempo foi a referência para Circuit Breaker em Java, entrou em modo de manutenção em 2018. A alternativa moderna e ativamente mantida é o Resilience4j, uma biblioteca leve, sem dependências externas e com suporte nativo a programação reativa.
O exemplo abaixo mostra uma implementação típica com Spring Boot:
// Dependência no pom.xml:
// io.github.resilience4j:resilience4j-spring-boot3:2.2.0
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class PagamentoService {
private final RestTemplate restTemplate;
public PagamentoService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@CircuitBreaker(name = "pagamento", fallbackMethod = "fallbackPagamento")
public String processarPagamento(String payload) {
// Chamada ao serviço externo de pagamento
return restTemplate.postForObject("https://api.pagamento.com/processar", payload, String.class);
}
// Chamado automaticamente quando o circuito está aberto ou ocorre uma exceção
public String fallbackPagamento(String payload, Exception ex) {
return "Serviço de pagamento temporariamente indisponível. Tente novamente em instantes.";
}
}
A configuração do circuito fica no application.yml:
resilience4j:
circuitbreaker:
instances:
pagamento:
# Janela deslizante baseada em contagem de requisições
slidingWindowType: COUNT_BASED
slidingWindowSize: 10
# Abre o circuito se mais de 50% das chamadas falharem
failureRateThreshold: 50
# Tempo em estado aberto antes de tentar half-open (em ms)
waitDurationInOpenState: 10000
# Número de chamadas permitidas no estado half-open
permittedNumberOfCallsInHalfOpenState: 3
# Mínimo de chamadas antes de avaliar a taxa de falhas
minimumNumberOfCalls: 5
Com essa configuração, o circuito precisa de no mínimo 5 chamadas para começar a avaliar. Se mais de 50% delas falharem em uma janela de 10 requisições, o circuito abre por 10 segundos, depois testa com 3 chamadas antes de decidir se fecha ou reabre.
O que configurar com cuidado
Os parâmetros padrão raramente são os ideais para produção. Alguns pontos que merecem atenção:
Tamanho da janela deslizante. Uma janela muito pequena torna o circuito nervoso — ele abre com poucos dados. Uma janela grande demora a reagir a degradações reais. O tipo TIME_BASED (janela de tempo) costuma ser mais estável que COUNT_BASED em serviços com tráfego irregular.
Tempo em estado aberto. Deve ser longo o suficiente para que o serviço de destino se recupere, mas não tão longo que prejudique a experiência do usuário desnecessariamente. Em serviços com reinicializações automáticas (Kubernetes, por exemplo), 10 a 30 segundos costumam funcionar bem.
Quais exceções contar como falha. Por padrão, o Resilience4j conta qualquer exceção não tratada. Mas erros de negócio — uma validação que falhou, um registro não encontrado — provavelmente não devem contar como falha do circuito. Use ignoreExceptions para excluí-los:
resilience4j:
circuitbreaker:
instances:
pagamento:
ignoreExceptions:
- com.exemplo.excecoes.ValidacaoException
- com.exemplo.excecoes.RecursoNaoEncontradoException
Monitoramento é parte do padrão
Um Circuit Breaker sem observabilidade é incompleto. Saber que o circuito abriu é tão importante quanto ele ter aberto.
O Resilience4j expõe métricas via Micrometer, o que permite integração direta com Prometheus e dashboards no Grafana. As métricas mais relevantes são resilience4j_circuitbreaker_state (estado atual), resilience4j_circuitbreaker_calls_total (total de chamadas por resultado) e resilience4j_circuitbreaker_failure_rate (taxa de falha em tempo real).
Além das métricas, log estruturado nos eventos de transição de estado (fechado → aberto, aberto → meio-aberto) é essencial para correlacionar incidentes com o comportamento do circuito.
Armadilhas comuns
Fallback que também falha. O método de fallback precisa ser simples e confiável — geralmente retorna um valor em cache, um dado padrão ou uma mensagem amigável. Se o fallback chamar outro serviço externo, você pode estar criando um segundo ponto de falha no momento em que o sistema já está sob estresse.
Circuito aberto mascarando o problema. O Circuit Breaker protege o sistema, mas não conserta o serviço problemático. Os alertas de monitoramento precisam continuar disparando mesmo quando o circuito está aberto, para que o time de operações saiba que há algo para investigar.
Configuração homogênea para serviços heterogêneos. Um serviço de autenticação e um serviço de recomendação têm perfis de tráfego, SLAs e tolerâncias a falha completamente diferentes. Cada circuito deve ser calibrado individualmente.
Indo além
O Circuit Breaker é frequentemente combinado com outros padrões de resiliência: Retry (novas tentativas com backoff exponencial), Rate Limiter (controle de taxa de requisições) e Bulkhead (isolamento de recursos por serviço). O Resilience4j suporta todos eles e permite combiná-los via anotações ou configuração.
Para aprofundamento, as leituras mais valiosas são o artigo original de Fowler, a documentação do Resilience4j e o livro Release It! de Michael Nygard, que discute o padrão — e muitos outros mecanismos de estabilidade — com profundidade e exemplos reais de produção.