Circuit breaker: o padrão que impede uma falha de derrubar o sistema inteiro
Quando um serviço externo cai, insistir nele só piora. Como o disjuntor funciona, os três estados, um exemplo em PHP e quando ele não vale a pena.

A API de pagamento parou de responder. Cada requisição do seu sistema fica esperando o tempo limite, segurando uma conexão com o banco, uma thread e memória. Em poucos minutos, a lentidão de um serviço de fora virou a lentidão do seu sistema inteiro, inclusive das telas que nem dependem de pagamento. O padrão circuit breaker existe para esse momento.
A ideia, como descreve o catálogo de padrões de arquitetura da Microsoft, é bloquear por um tempo o acesso a um serviço depois que as falhas passam de um limite, em vez de continuar tentando uma operação que provavelmente vai falhar. O nome vem do disjuntor elétrico: quando a corrente passa do limite, ele desarma e protege o resto da casa.
Os três estados do disjuntor
O circuit breaker funciona como um intermediário entre o seu código e o serviço, e se comporta como uma máquina de estados:
- Fechado: as chamadas passam normalmente, e o disjuntor conta as falhas recentes. Se elas passarem de um limite dentro de um intervalo, ele abre.
- Aberto: as chamadas falham na hora, sem nem tentar o serviço. Um cronômetro começa a correr.
- Meio-aberto: quando o cronômetro vence, algumas chamadas passam como teste. Se derem certo, o disjuntor fecha e zera a contagem; se uma falhar, ele volta a abrir e o cronômetro recomeça.
O estado meio-aberto é o detalhe que faz diferença. Um serviço que acabou de voltar costuma aguentar pouco tráfego, e soltar toda a fila de uma vez pode derrubá-lo de novo. Por isso só uma parte das chamadas passa até ele provar que se recuperou.

Um exemplo em PHP
Uma versão mínima, guardando o estado em memória, para mostrar a lógica. Em produção, com vários processos, o estado precisa morar num lugar compartilhado, como o Redis ou o banco:
final class CircuitBreaker
{
private int $falhas = 0;
private ?int $abertoAte = null;
public function __construct(
private int $limite = 5,
private int $segundosAberto = 30,
) {}
public function chamar(callable $operacao): mixed
{
if ($this->abertoAte !== null && time() < $this->abertoAte) {
throw new RuntimeException('Serviço indisponível: circuito aberto.');
}
try {
$resultado = $operacao(); // fechado, ou meio-aberto testando
$this->falhas = 0;
$this->abertoAte = null;
return $resultado;
} catch (Throwable $e) {
if (++$this->falhas >= $this->limite || $this->abertoAte !== null) {
$this->abertoAte = time() + $this->segundosAberto;
}
throw $e;
}
}
}Quando o tempo de abertura vence, a próxima chamada passa como teste (o meio-aberto): se der certo, tudo zera; se falhar, o circuito abre de novo na hora, sem esperar outras cinco falhas. Quem chama precisa tratar a exceção de circuito aberto com uma resposta útil: um valor guardado em cache, uma funcionalidade reduzida ou uma mensagem pedindo para tentar mais tarde.
Circuit breaker e retry são coisas diferentes
O padrão de retry tenta de novo esperando que a operação acabe dando certo, e serve para falhas passageiras, como uma conexão que oscilou. O circuit breaker faz o contrário: impede de tentar o que provavelmente vai falhar. Os dois podem trabalhar juntos, com o retry chamando a operação através do disjuntor, desde que o retry pare de insistir quando o disjuntor avisar que a falha não é passageira.

O que pesa na hora de implementar
O catálogo da Microsoft lista os cuidados. Os que mais pegam no dia a dia:
O tipo de falha importa. Um serviço fora do ar e um serviço sobrecarregado que estoura o tempo limite pedem limites diferentes. E uma resposta 429 ou 503 pode trazer quanto tempo esperar, o que permite abrir o circuito na hora, sem contar falha por falha.
Um disjuntor por dependência de verdade. Se o banco tem vários shards e um deles caiu, um disjuntor único para todos bloqueia também os que estão funcionando.
O tempo limite do serviço externo. Se ele for longo demais, o disjuntor demora a perceber a falha, e as threads ficam presas esperando antes de ele abrir.
Observabilidade. Cada troca de estado é um evento que vale registrar e alertar: um circuito aberto é um aviso antecipado de que uma dependência caiu.
Quando não usar
O padrão acrescenta complexidade, e nem sempre compensa. Não faz sentido para recursos locais, como estruturas em memória; não substitui o tratamento de exceção da regra de negócio; e pode sobrar em arquitetura orientada a mensagens, que já manda a mensagem que falhou para uma fila de mortas (dead letter queue). Também é redundante quando a infraestrutura já cuida disso, como num service mesh ou num balanceador com health check.
Onde ele brilha é na fronteira com o que você não controla: a API de pagamento, o serviço de e-mail, o parceiro que cai toda sexta à tarde. Ali, falhar rápido é melhor que falhar devagar levando o sistema junto.
Fonte: Microsoft Azure Architecture Center: Circuit Breaker pattern
Produzido com auxílio de IA e revisado pela redação.
Comentários (0)
Ainda não há comentários. Comece a conversa.




Deixe seu comentário