Circuit Breaker
Padrão de resiliência que interrompe chamadas a um serviço com falha para evitar cascata de erros e dar tempo para o serviço se recuperar. Inspirado nos disjuntores elétricos, protege o sistema chamador de ficar preso esperando por um serviço que não vai responder.
Intenção
O Circuit Breaker detecta falhas repetidas em um serviço externo e, ao atingir um threshold, "abre o disjuntor" — rejeitando chamadas imediatamente sem tentar alcançar o serviço com falha. Isso evita que o tempo de espera por um serviço degradado se propague para o serviço chamador, transformando uma falha pontual em cascata de erros no sistema inteiro.
A analogia com o disjuntor elétrico é precisa: quando a corrente excede o limite seguro, o disjuntor "abre" e interrompe o circuito para proteger a fiação. Da mesma forma, o Circuit Breaker de software "abre" e interrompe chamadas para proteger o sistema chamador. Depois de um período, permite testar se o serviço se recuperou antes de voltar ao funcionamento normal.
Problema
Em sistemas distribuídos, chamadas a serviços externos falham. Timeouts de rede, reinicializações, picos de carga, deploys com bugs — todos esses eventos são previsíveis e inevitáveis. O problema não é a falha em si, mas o que acontece com o sistema chamador quando a falha persiste:
- Threads presas em timeout: cada chamada que aguarda resposta de um serviço degradado ocupa uma thread ou conexão. Se o serviço demora 30 segundos para dar timeout e chegam 100 requisições por segundo, em instantes o pool de threads está esgotado e o sistema chamador para de responder — mesmo para funcionalidades que não dependem do serviço com falha.
- Cascata de erros: o Serviço A chama o Serviço B, que chama o Serviço C. O Serviço C está lento. O Serviço B começa a acumular timeouts. O Serviço A começa a acumular timeouts esperando o Serviço B. A falha de um serviço folha derruba toda a cadeia de chamadas.
- Retry que piora o problema: sistemas com retry automático bombardeiam o serviço já sobrecarregado com mais tentativas, impedindo a recuperação e transformando uma instabilidade temporária em indisponibilidade prolongada.
- Degradação invisível: sem monitoramento explícito do estado das dependências, a aplicação continua tentando chamadas que falham com timeout completo, respondendo lentamente para todos os usuários em vez de falhar rápido para os afetados e continuar funcionando para os demais.
Como funciona
Máquina de estados: CLOSED, OPEN e HALF-OPEN
O Circuit Breaker é essencialmente uma máquina de três estados que envolve as chamadas a um serviço externo. O estado atual determina se a chamada passa, é rejeitada imediatamente ou é usada como sonda de recuperação.
falhas > threshold
┌──────────┐ ────────────────────────► ┌──────────┐
│ │ │ │
│ CLOSED │ │ OPEN │
│ (normal) │ ◄────────────────────── │(disjuntor│
│ │ sucesso suficiente │ aberto) │
└──────────┘ em HALF-OPEN └────┬─────┘
│
│ timer expirou
▼
┌──────────┐
│HALF-OPEN │
│ (sondagem│
│ ) │
└──────────┘
falha → volta a OPEN
CLOSED : chamadas passam normalmente. Falhas são contadas.
OPEN : chamadas rejeitadas imediatamente (fail-fast). Timer ativo.
HALF-OPEN: número limitado de chamadas de teste passa. Resultado
determina transição para CLOSED (recuperado) ou OPEN (ainda falho).
Estado CLOSED — funcionamento normal
Todas as chamadas passam para o serviço downstream. O Circuit Breaker monitora os resultados: erros (exceções, timeouts, respostas com status 5xx) incrementam um contador de falhas. Quando o percentual de falhas dentro de uma janela de tempo excede o failure threshold configurado, o circuito transiciona para OPEN.
Estado OPEN — disjuntor ativado
Nenhuma chamada chega ao serviço downstream. O Circuit Breaker rejeita a requisição imediatamente — fail-fast — sem esperar por timeout. Um timer é iniciado. A resposta ao chamador pode ser um erro explícito ou, preferivelmente, um fallback (dado em cache, valor padrão, resposta degradada). O timer define quanto tempo o circuito permanece aberto antes de tentar se recuperar.
Estado HALF-OPEN — sondagem de recuperação
Após o timer expirar, o circuito entra em HALF-OPEN. Um número limitado de chamadas de teste é permitido. Se essas chamadas forem bem-sucedidas e atingirem o success threshold, o circuito fecha (CLOSED) e o funcionamento normal é retomado. Se qualquer chamada de teste falhar, o circuito reabre (OPEN) e o timer é reiniciado.
Parâmetros críticos
- Failure threshold: percentual ou número absoluto de falhas dentro de uma janela de tempo para acionar a abertura. Ex.: 50% de erros em uma janela deslizante de 60 segundos com mínimo de 10 chamadas.
- Timeout (sleep duration): quanto tempo o circuito permanece OPEN antes de ir para HALF-OPEN. Deve ser suficiente para o serviço downstream se recuperar — tipicamente entre 10 segundos e alguns minutos.
- Success threshold em HALF-OPEN: quantas chamadas bem-sucedidas consecutivas (ou percentual) são necessárias para fechar o circuito. Evita fechar prematuramente com base em apenas uma chamada de sucesso.
Fallback: degradação graciosa
Fail-fast sem fallback apenas substitui um erro lento por um erro rápido — a experiência do usuário melhora em latência, mas não em funcionalidade. O verdadeiro valor do Circuit Breaker está em combiná-lo com uma estratégia de fallback:
- Cache stale: retornar o último valor cacheado, mesmo que desatualizado.
- Valor padrão: retornar um resultado genérico quando personalização não é crítica.
- Resposta degradada: retornar uma versão simplificada da funcionalidade.
- Erro explícito e rápido: quando não há fallback aceitável, ao menos falhar em milissegundos em vez de segundos.
Circuit Breaker vs Retry
Retry e Circuit Breaker são complementares, não substitutos. Retry tenta a operação novamente imediatamente — útil para falhas transientes de rede, mas prejudicial quando o serviço está sobrecarregado (mais chamadas pioram a situação). Circuit Breaker para de tentar por um período inteiro, dando espaço para recuperação.
A combinação comum é: Retry com backoff exponencial (tenta algumas vezes com espera crescente entre tentativas) dentro do contexto de um Circuit Breaker (se os retries continuam falhando além do threshold, o circuito abre e para de tentar completamente por um período).
Quando usar
- Chamadas síncronas a serviços externos: APIs de terceiros, microsserviços downstream, serviços de pagamento — qualquer chamada de rede que pode falhar ou ficar lenta. O Circuit Breaker protege o chamador de ficar preso aguardando por um serviço degradado.
- Arquiteturas de microsserviços: quando há dependências entre serviços, a falha de um pode cascatear. Circuit Breaker em cada ponto de integração é uma prática padrão de resiliência.
- Serviços com padrão de falha estável: quando o serviço tem histórico de falhas periódicas com recuperação previsível, o threshold pode ser calibrado para abrir no momento certo e fechar quando o serviço se recupera.
Quando evitar
- Chamadas locais ou intra-processo: banco de dados na mesma rede privada com latência abaixo de 1ms, chamadas entre módulos do mesmo processo. O overhead do Circuit Breaker não se justifica quando não há risco real de timeout prolongado.
- Serviços sem padrão de falha estável: se o serviço downstream raramente falha com consistência suficiente para atingir o threshold, o Circuit Breaker nunca abre e não agrega valor — mas adiciona complexidade.
- Operações críticas sem fallback aceitável: se não há resposta degradada possível e a operação é bloqueante para o fluxo do usuário, o Circuit Breaker ainda ajuda em latência, mas o benefício de UX é limitado. Nesses casos, a prioridade deve ser melhorar a confiabilidade do serviço.
Prós e contras
Prós
- Previne cascata de falhas: isola a falha no ponto de integração, evitando que se propague para o resto do sistema.
- Fail-fast: o chamador recebe uma resposta imediata (erro ou fallback) em vez de esperar pelo timeout completo, melhorando a latência percebida.
- Proteção do serviço downstream: ao parar de enviar requisições para um serviço sobrecarregado, dá espaço para ele se recuperar sem ser bombardeado.
- Degradação graciosa: combinado com fallback, o sistema continua funcionando de forma limitada em vez de falhar completamente.
- Visibilidade: o estado do circuito (OPEN/CLOSED) é uma métrica operacional valiosa — indica problemas de dependência em tempo real.
Contras
- Complexidade adicional: implementar e calibrar os parâmetros (threshold, timeout, success threshold) requer conhecimento do comportamento das dependências.
- Falsos positivos: threshold mal calibrado abre o circuito em picos normais de latência, causando degradação desnecessária.
- Estado distribuído: em sistemas com múltiplas instâncias, cada instância tem seu próprio Circuit Breaker. O estado não é compartilhado — uma instância pode ter o circuito aberto enquanto outra ainda está tentando.
- Fallback requer manutenção: a lógica de fallback precisa ser implementada, testada e mantida ao longo da vida do sistema.
Armadilhas comuns
1. Threshold muito baixo
Um failure threshold de 10% pode parecer conservador, mas em momentos de pico normal, a taxa de erros transitórios pode superar esse valor brevemente. O circuito abre, rejeita chamadas legítimas e o serviço downstream não estava realmente com problema — o problema foi a calibração. Comece com threshold mais permissivo (50%) e ajuste com dados reais de produção.
2. Timeout muito curto no estado OPEN
Se o serviço downstream precisa de 2 minutos para se recuperar após um pico, um sleep duration de 10 segundos faz o circuito ir para HALF-OPEN cedo demais. A chamada de sonda falha, o circuito reabre por mais 10 segundos, e o ciclo se repete — flapping do circuito — sem dar tempo real para a recuperação acontecer. O timeout deve ser estimado com base no histórico de recuperação do serviço.
3. Sem fallback definido
Circuit Breaker em estado OPEN sem fallback retorna um erro 5xx instantâneo em vez do erro lento original. A latência melhorou, mas a experiência do usuário é a mesma — um erro. O ganho real do padrão só se materializa quando há uma resposta de fallback que permite ao sistema continuar funcionando de forma degradada mas útil.
4. Circuit Breaker sem observabilidade
Se o circuito abrir silenciosamente em produção e não houver alerta, a equipe descobre o problema quando usuários reclamam — e talvez depois de muito tempo. O estado do circuito (OPEN/HALF-OPEN/CLOSED), as métricas de failure rate e o número de chamadas rejeitadas devem ser expostos como métricas monitoradas com alertas configurados.
Regra prática: se o Circuit Breaker não está gerando métricas e alertas, ele não está completo. O padrão serve tanto para resiliência quanto para observabilidade — um circuito aberto é um sinal de que algo precisa de atenção imediata.
Arquiteturas e padrões relacionados
- Event-Driven Architecture
- Escalabilidade Horizontal vs Vertical
- Filas de Mensagem
- REST vs GraphQL vs gRPC
Event-Driven Architecture e Circuit Breaker resolvem o mesmo problema de formas opostas: o Circuit Breaker protege chamadas síncronas (request/response), enquanto a arquitetura orientada a eventos elimina o acoplamento síncrono ao fazer comunicação assíncrona via mensagens. Em sistemas que misturam os dois estilos, o Circuit Breaker protege os pontos onde a chamada síncrona ainda é necessária.
Filas de Mensagem são uma alternativa estrutural: ao invés de chamar o serviço diretamente (e precisar de Circuit Breaker para se proteger), a mensagem vai para a fila e o serviço a processa quando disponível. O Circuit Breaker trata o sintoma; a fila pode eliminar a causa ao desacoplar produtor e consumidor.