Construindo um Mecanismo de Circuit Breaker Utilizando .NET
Introdução ao Padrão Circuit Breaker
O padrão Circuit Breaker é uma técnica utilizada no desenvolvimento de software para aumentar a resiliência de aplicações, especialmente em arquiteturas distribuídas (PUNITHAVATHY; PRIYA, 2024). Esse padrão atua como um interruptor que impede que chamadas a serviços falhem repetidamente, permitindo que o sistema se recupere antes de tentar uma nova chamada. Isso é especialmente útil em cenários onde a latência e a falha de serviços externos podem impactar a performance da aplicação. Em essência, o Circuit Breaker ajuda a evitar que um sistema inteiro falhe devido a problemas em um único componente.
Propósito
O Circuit Breaker é inspirado nos sistemas elétricos, onde um circuito pode ser interrompido para evitar sobrecargas. No contexto de software, ele funciona de maneira semelhante, permitindo que o sistema "desligue" as chamadas a um serviço que está falhando (PUNITHAVATHY; PRIYA, 2024). Isso evita que falhas em um serviço afetem todo o sistema, permitindo que ele se recupere antes de retomar as operações normais (FOWLER, 2014). Dessa forma, podemos considerar que o Circuit Breaker é:
- Um mecanismo que previne chamadas repetidas a serviços instáveis, protegendo o sistema de falhas em cascata.
- Inspirado em disjuntores elétricos, "abrindo" o circuito quando detecta falhas contínuas.
- Composto por três estados: Closed (normal), Open (chamadas bloqueadas) e Half-Open (teste para retomar operações) (POLLY, 2023).
- Utilizado para melhorar a estabilidade e resiliência de aplicações distribuídas (MICROSOFT, 2025).
Da mesma forma, é importante entender que o Circuit Breaker não é:
- Um mecanismo de retry simples: embora possa ser combinado com retries, sua função principal é interromper chamadas a serviços problemáticos.
- Um substituto para fallback: embora possa ser usado em conjunto com estratégias de fallback, eles têm propósitos distintos.
- Uma ferramenta de monitoramento: embora forneça informações sobre falhas, não substitui sistemas de observabilidade.
- Balanceador de carga: sua função é interromper chamadas a serviços instáveis, não distribuir tráfego entre serviços saudáveis.
Por Que Usar Circuit Breaker?
Quando um serviço externo falha, as chamadas subsequentes a esse serviço podem causar sobrecarga e latência desnecessárias, levando a um efeito cascata que pode comprometer a estabilidade da aplicação (COSTA et al., 2022). O padrão Circuit Breaker ajuda a evitar essa situação, protegendo a aplicação de falhas em cascata. Ele permite que a aplicação reaja rapidamente a problemas, liberando recursos e permitindo que o sistema se recupere mais rapidamente. Além disso, o Circuit Breaker pode ser configurado para fornecer feedback ao usuário, como mensagens de erro amigáveis, em vez de falhas silenciosas ou mensagens de erro genéricas.
Em um mundo onde a dependência de serviços externos é cada vez mais comum, a implementação de um Circuit Breaker se torna uma prática recomendada (COSTA et al., 2022). Ele não só melhora a resiliência da aplicação, mas também facilita o monitoramento e a manutenção do sistema, permitindo que as equipes de desenvolvimento identifiquem rapidamente problemas que podem surgir devido a falhas externas.
Implementando Circuit Breaker em .NET
Para implementar um mecanismo de Circuit Breaker em .NET, podemos usar a biblioteca Polly, que é uma biblioteca de resiliência para .NET que facilita a implementação de padrões como retry, timeout e circuit breaker. O Polly fornece uma API poderosa e flexível, permitindo que os desenvolvedores configurem políticas de resiliência que atendam às necessidades específicas de suas aplicações (PUNITHAVATHY; PRIYA, 2024).
Instalação do Polly
Para começar a usar o Polly, devemos instalar o pacote Polly via NuGet (POLLY, 2023). Isso pode ser feito através do console do NuGet com o seguinte comando:
Install-Package Polly
Alternativamente, você pode instalar o Polly utilizando o gerenciador de pacotes do Visual Studio. Basta procurar por "Polly" na seção de pacotes NuGet e clicar em instalar. Uma vez que o Polly está instalado, você pode começar a implementar suas políticas de resiliência em sua aplicação.
Configurando o Circuit Breaker
Após a instalação, podemos configurar um Circuit Breaker. O código a seguir demonstra como criar uma política de Circuit Breaker que abre o circuito após 3 falhas consecutivas e o mantém aberto por 30 segundos. Essa configuração é um ponto de partida e pode ser ajustada de acordo com as necessidades específicas de sua aplicação.
using Polly;
using System;
using System.Net.Http;
using System.Threading.Tasks;
public class CircuitBreakerExample
{
private static readonly HttpClient httpClient = new HttpClient();
public async Task<string> FetchDataAsync(string url)
{
var circuitBreakerPolicy = Policy
.Handle<HttpRequestException>()
.CircuitBreaker(3, TimeSpan.FromSeconds(30));
try
{
return await circuitBreakerPolicy.ExecuteAsync(async () =>
{
var response = await httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
});
}
catch (BrokenCircuitException)
{
return "Circuit is open. Please try again later.";
}
}
}
Neste exemplo, estamos usando a política de Circuit Breaker do Polly para definir que, se ocorrerem três falhas consecutivas ao tentar acessar um URL, o circuito será aberto e permanecerá assim por 30 segundos. Durante esse tempo, qualquer tentativa de acesso ao serviço resultará em uma exceção BrokenCircuitException
, que pode ser tratada para informar ao usuário que o serviço está temporariamente indisponível.
Testando o Circuit Breaker
Para testar o comportamento do Circuit Breaker, você pode simular chamadas a um serviço que falha. Aqui está um exemplo de como você poderia escrever um teste simples para verificar se o Circuit Breaker está funcionando conforme o esperado:
public async Task TestCircuitBreaker()
{
var circuitBreakerExample = new CircuitBreakerExample();
for (int i = 0; i < 10; i++)
{
var result = await circuitBreakerExample.FetchDataAsync("http://example.com/fail");
Console.WriteLine(result);
}
}
Neste teste, estamos chamando um serviço que sabemos que falhará. Após três falhas, o Circuit Breaker deve abrir e as tentativas subsequentes de chamada ao serviço devem resultar na mensagem "Circuit is open. Please try again later." sendo impressa no console. Isso confirma que o Circuit Breaker está funcionando conforme o esperado e que está protegendo a aplicação de sobrecargas desnecessárias.
Monitorando o Circuit Breaker
Monitorar o estado do Circuit Breaker é crucial para entender o desempenho da sua aplicação. O Polly permite que você registre eventos de estado do Circuit Breaker, o que pode ser extremamente útil para depuração e manutenção. Aqui está um exemplo de como fazer isso:
var circuitBreakerPolicy = Policy
.Handle<HttpRequestException>()
.CircuitBreaker(
handledEventsAllowedBeforeBreaking: 3,
durationOfBreak: TimeSpan.FromSeconds(30),
onBreak: (exception, breakDelay) =>
{
Console.WriteLine(
$"[OPEN] Circuit opened due to: {exception.Message}. Waiting {breakDelay.TotalSeconds} seconds before retrying.");
},
onReset: () =>
{
Console.WriteLine(
"[CLOSED] Circuit closed. Operations resumed successfully.");
},
onHalfOpen: () =>
{
Console.WriteLine(
"[HALF-OPEN] Circuit is half-open. Testing service availability...");
});
Neste exemplo, estamos adicionando dois manipuladores de eventos: um para quando o circuito é aberto (onBreak) e outro para quando o circuito é redefinido (onReset). Esses eventos permitem que você registre informações sobre o estado do Circuit Breaker, ajudando a identificar padrões de falhas e a ajustar as configurações conforme necessário.
Conclusão
O padrão Circuit Breaker contribui no aumento da resiliência de aplicações .NET. Usando a biblioteca Polly, é possível implementar essa técnica de forma simples e eficiente. Monitorar o estado do Circuit Breaker e ajustar suas configurações são passos fundamentais para garantir que sua aplicação continue a funcionar de maneira confiável, mesmo em face de falhas externas. Ao integrar o Circuit Breaker em sua estratégia de desenvolvimento, você estará proporcionando uma base mais robusta e segura para suas aplicações, melhorando a experiência do usuário e a confiabilidade do sistema a longo prazo.
Referências
-
PUNITHAVATHY, E.; PRIYA, N. Comparative Study of Static Resilience Patterns Over Dynamically Modified Resilience Patterns. 2024.
-
PUNITHAVATHY, E.; PRIYA, N. Auto retry circuit breaker for enhanced performance in microservice applications. International Journal of Electrical & Computer Engineering (2088-8708), v. 14, n. 2, 2024.
-
COSTA, Thiago M. et al. Avaliação de Desempenho de Dois Padrões de Resiliência para Microsserviços: Retry e Circuit Breaker. In: Simpósio Brasileiro de Redes de Computadores e Sistemas Distribuídos (SBRC). SBC, 2022. p. 517-530.
-
POLLY, GitHub. Polly: The .NET resilience and transient-fault-handling library. Disponível em: https://www.pollydocs.org . Acesso em: 15 abril. 2025.
-
FOWLER, M. Circuit Breaker. 2014. Disponível em https://martinfowler.com/bliki/CircuitBreaker.html. Acesso em: 15 abril. 2025.
-
MICROSOFT. Circuit Breaker pattern. Disponível em https://learn.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker. Acesso em: 15 abril. 2025.