Circuit Breaker

22/09/2024

Imagine um serviço que está com algum problema para processar as requisições e acaba retornando timeouts. Neste caso, ficar fazendo a mesma requisição pode degradar ainda mais o serviço e acabar consumindo recursos desnecessários. Além disso, este serviço problemático pode acabar desencadeando falhas em cascata em todos os serviços que fazem parte da mesma requisição.

O padrão Circuit Breaker pode resolver esse problema, bloqueando as chamadas que estão fadadas à falharem.

Podemos traduzir circuit breaker para disjuntor, e o princípio é o mesmo:

Detectar uso excessivo, falhar primeiro e abrir o circuito. Mais abstratamente, o Circuit Breaker existe para permitir que um subsistema (um circuito elétrico) falhe (consumo excessivo de corrente, possivelmente de um curto-circuito) sem destruir o sistema inteiro (a casa). Além disso, uma vez que o perigo tenha passado, o disjuntor pode ser reiniciado para restaurar a função completa do sistema.

Texto retirado do livro Release It! (Michael Nygaard 2018)

Veja o seguinte cenário, o serviço Orders se comunica com o serviço Payments que se comunica com o Payment Gateway:

Cenário de Exemplo

Se por algum motivo o Payment Gateway demorar para responder e retornar um timeout, teremos uma falha no Payments que também irá retornar um timeout e desencadear uma falha no Orders.

Essas falhas em cascata irão acontecer para todas as requisições, mesmo sabendo que nenhuma delas vão conseguir completar com sucesso e isso é um problema, pois uma vez que sabemos que o Payment Gateway está com problemas, podemos falhar antes e evitar o gasto de recursos desnecessário até que o Payment Gateway volte ao seu estado normal.

Cenário de Exemplo com Timeout

Para resolver isso podemos utilizar o circuit breaker para lidar com essa comunicação entre Payments e Payment Gateway.

Diagrama do Circuit Breaker

O circuit breaker possui 3 estados:

Closed: Todas as requisiçẽs irão passar. Se a chamada retornar algum erro, um contador será incrementado. Caso nenhum erro seja retornado, o contador será resetado. Se o contador atingir um limite, o estado é alterado para Open.

Open: Todas as requisições falham imediatamente, sem que qualquer chamada seja realizada. A falha pode ser um retorno de uma mensagem para que o cliente entenda o que aconteceu. Após um período de tempo o estado é alterado para Half-Open.

Half-Open: Quando este estado está ativo, a próxima requisição irá tentar chamar o serviço com problema, se a chamada retornar um erro, o estado volta para Open. Caso nenhum erro seja retornado, o contador é resetado e o estado é alterado para Closed.

Veja como fica o diagrama de sequência com o circuit breaker:

Diagrama de sequência com Circuit Breaker

Veja que o serviço problemático (Payment Gateway) nem foi chamado, pois a requisição anterior pegou o timeout e disparou o circuit breaker que alterou o estado para Open. Com isso as próximas requisições não serão liberadas pelo circuit breaker, neste caso uma mensagem de erro pode ser retornada.

Também quando o circuit breaker está no estado Open, ao invés de retornar uma mensagem, podemos definir alguma estratégia de alternativa, por exemplo, podemos definir para que o circuit breaker chame um outro Payment Gateway para tentar completar o pagamento sem que o cliente seja afetado.

Diagrama de sequência com Circuit Breaker e Fallback

Entretanto esta é uma decisão que deve ser tomada levando em conta as decisões de negócio. Dependendo das regras de negócio é necessário saber se é aceitável pensar em alternativas caso a primeira opção falhe.

Por fim, todas as alterações de estado no circuit breaker precisam ser logadas e monitoradas. A frequência que um circuit breaker altera seu estado pode ser uma ótima métrica para identificar possíveis problemas. Também é possível medir a quantidade de chamadas e tempos de respostas com um circuit breaker.

Links Úteis