# Como usar Polly para retry e circuit breaker ao consultar CPF em .NET

> Implemente retry e circuit breaker com Polly ao consultar a API de CPF em .NET para maior resiliência e disponibilidade.

**Publicado:** 16/10/2024
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/como-usar-polly-retry-circuit-breaker-consultar-cpf-dotnet

---


O Polly é a biblioteca de resiliência padrão para .NET que permite implementar retry com backoff exponencial e circuit breaker em chamadas à API de CPF, garantindo que falhas temporárias de rede não interrompam o fluxo de validação e que o sistema se recupere automaticamente sem intervenção manual.

## Introdução

Ao consumir APIs externas como a do CPFHub.io, falhas temporárias de rede, timeouts e sobrecarga do servidor são situações inevitáveis. O Polly é uma biblioteca de resiliência para .NET que permite implementar padrões como retry com backoff exponencial e circuit breaker.

---

## Instalando e configurando o Polly

Adicione o pacote Polly ao seu projeto junto com a extensão para `IHttpClientFactory`:

```csharp
dotnet add package Microsoft.Extensions.Http.Polly
dotnet add package Polly.Extensions.Http
```

O Polly se integra nativamente ao `IHttpClientFactory` do ASP.NET Core, permitindo aplicar políticas de resiliência diretamente na configuração do `HttpClient`.

---

## Implementando retry com backoff exponencial

O retry com backoff exponencial aguarda intervalos crescentes entre tentativas, reduzindo a carga no servidor durante instabilidades.

```csharp
using Polly;
using Polly.Extensions.Http;

public static class PollyPolicies
{
 public static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
 {
 return HttpPolicyExtensions
 .HandleTransientHttpError()
 .WaitAndRetryAsync(
 retryCount: 3,
 sleepDurationProvider: tentativa =>
 TimeSpan.FromSeconds(Math.Pow(2, tentativa)),
 onRetry: (outcome, timespan, tentativa, context) =>
 {
 Console.WriteLine(
 $"Tentativa {tentativa} após {timespan.TotalSeconds}s. " +
 $"Status: {outcome.Result?.StatusCode}");
 });
 }
}
```

| Tentativa | Intervalo | Tempo Total Acumulado |
|---|---|---|
| 1a | 2 segundos | 2s |
| 2a | 4 segundos | 6s |
| 3a | 8 segundos | 14s |

---

## Implementando circuit breaker

O circuit breaker interrompe chamadas à API quando detecta muitas falhas consecutivas, evitando sobrecarregar um serviço já instável.

```csharp
public static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
{
 return HttpPolicyExtensions
 .HandleTransientHttpError()
 .CircuitBreakerAsync(
 handledEventsAllowedBeforeBreaking: 5,
 durationOfBreak: TimeSpan.FromSeconds(30),
 onBreak: (outcome, breakDelay) =>
 {
 Console.WriteLine(
 $"Circuit aberto por {breakDelay.TotalSeconds}s. " +
 $"Razão: {outcome.Exception?.Message ?? outcome.Result?.StatusCode.ToString()}");
 },
 onReset: () =>
 {
 Console.WriteLine("Circuit fechado. Retomando chamadas normalmente.");
 },
 onHalfOpen: () =>
 {
 Console.WriteLine("Circuit semi-aberto. Testando próxima chamada.");
 });
}
```

---

## Combinando políticas com PolicyWrap

O verdadeiro poder do Polly está em combinar múltiplas políticas. Aplique retry dentro do circuit breaker para máxima resiliência.

```csharp
public static IAsyncPolicy<HttpResponseMessage> GetResiliencePolicy()
{
 var retryPolicy = GetRetryPolicy();
 var circuitBreakerPolicy = GetCircuitBreakerPolicy();

 return Policy.WrapAsync(retryPolicy, circuitBreakerPolicy);
}
```

Registre a política combinada no `Program.cs`:

```csharp
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHttpClient<ICpfApiClient, CpfApiClient>(client =>
{
 client.BaseAddress = new Uri("https://api.cpfhub.io/");
 client.DefaultRequestHeaders.Add("x-api-key",
 builder.Configuration["CpfHub:ApiKey"]);
 client.Timeout = TimeSpan.FromSeconds(10);
})
.AddPolicyHandler(PollyPolicies.GetResiliencePolicy());

builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
```

---

## Tratando o estado do circuit breaker

Quando o circuit breaker está aberto, é importante informar o usuário de forma adequada em vez de simplesmente falhar.

```csharp
[ApiController]
[Route("api/[controller]")]
public class CpfController : ControllerBase
{
 private readonly ICpfApiClient _cpfClient;

 public CpfController(ICpfApiClient cpfClient)
 {
 _cpfClient = cpfClient;
 }

 [HttpGet("{cpf}")]
 public async Task<IActionResult> Consultar(string cpf)
 {
 try
 {
 var resultado = await _cpfClient.ConsultarAsync(cpf);

 if (resultado is { Success: true })
 return Ok(resultado.Data);

 return NotFound(new { message = "CPF não encontrado" });
 }
 catch (Polly.CircuitBreaker.BrokenCircuitException)
 {
 return StatusCode(503, new
 {
 message = "Serviço temporariamente indisponível. Tente novamente em breve.",
 retryAfter = 30
 });
 }
 catch (Exception)
 {
 return StatusCode(502, new
 {
 message = "Erro ao consultar o serviço de CPF"
 });
 }
 }
}
```

---

## Perguntas frequentes

### Por que usar backoff exponencial em vez de intervalos fixos entre tentativas?
O backoff exponencial evita o efeito de "thundering herd": quando muitos clientes reagem a uma falha ao mesmo tempo com intervalos fixos, todos retentam juntos e ampliam a sobrecarga. Com intervalos crescentes (2s, 4s, 8s), o tráfego se distribui naturalmente e o serviço recupera com mais facilidade.

### Quando o circuit breaker deve ser usado junto com o retry?
Sempre que a API externa puder ficar indisponível por períodos prolongados. O retry lida com falhas transitórias curtas; o circuit breaker interrompe as tentativas quando o serviço está claramente fora do ar, poupando recursos e retornando respostas de fallback rapidamente ao invés de aguardar timeouts sucessivos.

### Como monitorar o estado do circuit breaker em produção?
Registre os eventos `onBreak`, `onReset` e `onHalfOpen` em um sistema de observabilidade como Application Insights, OpenTelemetry ou Serilog. A [documentação oficial do Polly](https://github.com/App-vNext/Polly) recomenda expor o estado atual como métrica para alertas automáticos quando o circuit abrir com frequência.

### A CPFHub.io bloqueia requisições quando o limite do plano é atingido?
Não. A CPFHub.io nunca retorna 429 nem bloqueia consultas ao atingir o limite mensal. O plano gratuito inclui 50 consultas/mês e, a partir da 51ª, cada consulta é cobrada a R$0,15. O plano Pro oferece 1.000 consultas por R$149/mês com o mesmo modelo de excedente.

### Leia também

- [SLA de API de CPF: níveis de disponibilidade e o que exigir do seu provedor](https://cpfhub.io/blog/sla-api-cpf-niveis-disponibilidade)
- [Como validar CPF no frontend com React e API REST](https://cpfhub.io/blog/como-validar-cpf-no-frontend-com-react-e-api-rest)
- [Timeout na API de CPF: como configurar e tratar corretamente](https://cpfhub.io/blog/timeout-na-api-de-cpf-como-configurar-e-tratar-corretamente)
- [API de CPF grátis para desenvolvedores: como começar em 5 minutos](https://cpfhub.io/blog/api-cpf-gratis-desenvolvedores-comecar-5-minutos)

---

## Conclusão

Implementar retry e circuit breaker com Polly é essencial para qualquer aplicação .NET que dependa de APIs externas. Essas políticas de resiliência garantem que falhas temporárias não comprometam a experiência do usuário e que o sistema se recupere automaticamente.

Cadastre-se em [cpfhub.io](https://www.cpfhub.io/) — 50 consultas mensais gratuitas, sem cartão de crédito — e comece a integrar a consulta de CPF com resiliência total na sua aplicação .NET.

