Olá! Seja bem-vindo de volta.
Na lição anterior, exploramos como usar o Aspire Dashboard para verificar a comunicação entre serviços e diagnosticar problemas através da análise de traces distribuídos. Vimos como uma falha, como um timeout, pode interromper o fluxo de uma solicitação. No entanto, em sistemas distribuídos complexos, muitas falhas são transitórias — problemas temporários de rede, uma sobrecarga momentânea do serviço, ou uma reinicialização rápida de um contêiner. Simplesmente falhar e retornar um erro ao usuário final nem sempre é a melhor abordagem.
A lição de hoje foca em como lidar com essas falhas de forma proativa. Nosso objetivo de aprendizagem é: implementar uma política de repetição (retry) padrão para a comunicação entre serviços usando Polly via Service Defaults do Aspire.
Construiremos sobre o que aprendemos sobre observabilidade, passando de uma postura reativa (diagnosticar falhas) para uma proativa (recuperar-se automaticamente delas), um princípio fundamental na engenharia de sistemas de alta disponibilidade.
O Desafio das Falhas Transitórias e o Padrão Retry
Em uma arquitetura de microsserviços, as chamadas de rede são inerentemente menos confiáveis do que as chamadas de método em processo. Um serviço pode estar temporariamente indisponível por inúmeras razões. O padrão de repetição (Retry Pattern) é uma estratégia fundamental para lidar com isso: em vez de falhar imediatamente, o serviço cliente tenta reenviar a mesma solicitação algumas vezes, na esperança de que a falha seja transitória e a próxima tentativa seja bem-sucedida.

Para implementar esse e outros padrões de resiliência em .NET, a biblioteca de referência é a Polly.
Polly e as Novas APIs de Resiliência do .NET 8
Polly é uma biblioteca de resiliência e tratamento de falhas transitórias para .NET. Com o .NET 8, a equipe do .NET colaborou com a comunidade Polly para criar uma nova API modernizada e de alto desempenho, integrada diretamente ao HttpClientFactory. Essa nova API está no pacote NuGet Microsoft.Extensions.Http.Resilience.
O vídeo a seguir, da conferência .NET Conf 2023, apresenta essa nova abordagem e a filosofia por trás dela.
Building resilient cloud services with .NET 8 | .NET Conf 2023
Este vídeo do canal oficial do .NET, 'Building resilient cloud services with .NET 8', explica a evolução da Polly e a nova integração com o .NET 8. Preste atenção em como as APIs foram modernizadas.
Assista aos trechos de 01:16 a 01:58 e de 03:27 a 07:31. O objetivo é entender: O que é a Polly e quais estratégias de resiliência ela oferece. As melhorias na Polly V8 e a introdução do novo pacote Microsoft.Extensions.Http.Resilience para simplificar a configuração de resiliência para HttpClient.
Configurando uma Política de Retry Personalizada
Para entender profundamente como o mecanismo de repetição funciona, vamos primeiro ver como configurar uma política personalizada usando as novas APIs. Isso nos dá controle total sobre o comportamento da repetição.
As principais configurações para uma política de repetição robusta são:
- Número de Tentativas (
MaxRetryAttempts): Quantas vezes reenviar a solicitação após a falha inicial. - Estratégia de Backoff (
BackoffType): O tempo de espera entre as tentativas. Uma espera constante não é ideal. A melhor prática é usar um backoff exponencial, onde o tempo de espera aumenta a cada nova tentativa (ex: 2s, 4s, 8s). Isso dá ao serviço sobrecarregado tempo para se recuperar. - Jitter: Adicionar uma pequena variação aleatória ao tempo de backoff. Isso é crucial para evitar o problema do "rebanho trovejante" (thundering herd), onde vários clientes, após uma falha, tentam se reconectar exatamente ao mesmo tempo, sobrecarregando novamente o serviço.
O vídeo a seguir demonstra de forma prática e detalhada como configurar uma política de repetição com essas opções.
Make Your HttpClient Resilient - Circuit Breaker, Retry, Timeout
No vídeo 'Make Your HttpClient Resilient', de Milan Jovanović, ele demonstra exatamente como adicionar e configurar uma política de repetição em um projeto .NET Aspire.
Assista ao trecho de 08:30 a 11:20. Observe como ele usa o método AddResilienceHandler para criar um pipeline customizado e, em seguida, chama AddRetry para configurar as opções MaxRetryAttempts, BackoffType.Exponential e UseJitter.
O código para adicionar um manipulador de resiliência personalizado a um HttpClient se parece com isto:
// Exemplo de configuração em um programa .NET
builder.Services.AddHttpClient<MyApiClient>()
.AddResilienceHandler("MyCustomPipeline", builder =>
{
builder.AddRetry(new HttpRetryStrategyOptions
{
MaxRetryAttempts = 3,
BackoffType = DelayBackoffType.Exponential,
UseJitter = true,
Delay = TimeSpan.FromSeconds(2) // Atraso base para o backoff
});
});
A Forma Aspire: AddStandardResilienceHandler e ServiceDefaults
Configurar políticas personalizadas é poderoso, mas requer conhecimento das melhores práticas. Felizmente, o .NET Aspire simplifica isso drasticamente. O projeto ServiceDefaults que o Aspire cria para você já inclui uma chamada que adiciona uma política de resiliência padrão e recomendada a todos os HttpClients registrados.
Isso é feito através do método de extensão AddStandardResilienceHandler().
Vamos consultar a documentação oficial para entender o que essa política padrão inclui.
Build resilient HTTP apps: Key development patterns - .NET
A documentação da Microsoft, 'Build resilient HTTP apps', é a fonte definitiva de informação. Vamos nos concentrar na seção que descreve a política de resiliência padrão.
Leia as seções 'Add standard resilience handler' e 'Standard resilience handler defaults'. Foque na tabela que detalha as cinco estratégias encadeadas. Anote especificamente os valores padrão para a estratégia 'Retry' (Max retries, Backoff, Use jitter, Delay).
Como você viu na documentação, o AddStandardResilienceHandler configura um pipeline com cinco estratégias, incluindo uma política de repetição com padrões sólidos:
| Ordem | Estratégia | Padrões da Política de Repetição |
|---|---|---|
| 3 | Retry | Max retries: 3 Backoff: Exponential Use jitter: true Delay: 2s |
Isso significa que, por padrão, qualquer HttpClient em um projeto Aspire já tentará reenviar uma solicitação falhada 3 vezes, com um backoff exponencial aleatório começando em 2 segundos. Isso é feito automaticamente para você, seguindo as melhores práticas da indústria, e é uma das grandes vantagens do Aspire para construir aplicações nativas da nuvem.
O vídeo de Milan Jovanović também ilustra esse ponto de forma excelente.
Make Your HttpClient Resilient - Circuit Breaker, Retry, Timeout
Para conectar tudo, vamos voltar ao vídeo de Milan Jovanović. Depois de criar a política customizada, ele mostra como o Aspire já fornece uma solução padrão.
Assista ao trecho de 17:10 a 19:05. Observe como ele comenta o código da política personalizada e simplesmente confia no AddStandardResilienceHandler que o .NET Aspire adiciona por padrão através do projeto ServiceDefaults. Isso demonstra como o Aspire encapsula essa complexidade para você.
Teste seu entendimento!
Você tem um serviço A que chama um serviço B usando um HttpClient em um projeto .NET Aspire. O serviço B está passando por uma instabilidade e 25% de suas requisições falham com um erro 503 Service Unavailable.
- Com a configuração padrão do .NET Aspire
ServiceDefaults, o que acontecerá quando o serviçoAencontrar um erro503ao chamarB? - Você decide que para esta chamada específica, 3 tentativas de repetição é muito agressivo. Você quer apenas 1 tentativa de repetição. Como você poderia sobrescrever o comportamento padrão para o
HttpClientespecífico que chama o serviçoB? (Dica: pense em como você configuraria uma política personalizada).
Show answer
- O
AddStandardResilienceHandler, aplicado por padrão pelo Aspire, trata os códigos de status da série 5xx. Portanto, a política de repetição será acionada. OHttpClientdo serviçoAtentará reenviar a requisição paraBaté 3 vezes adicionais, com um backoff exponencial e jitter entre as tentativas, antes de finalmente desistir e propagar a falha. - Para sobrescrever o padrão, você pode configurar uma política de resiliência específica para o
HttpClientdo serviçoB. Você não usariaAddStandardResilienceHandler. Em vez disso, você usariaAddResilienceHandlerpara definir um pipeline personalizado, onde você adicionaria uma políticaAddRetrycomMaxRetryAttempts = 1. Isso lhe daria controle granular sobre aquele cliente específico, enquanto outros clientes ainda usariam o padrão Aspire.
Conclusão
Nesta lição, você aprendeu como tornar suas aplicações distribuídas mais robustas implementando o padrão de repetição. Vimos que, embora seja possível configurar políticas de repetição altamente personalizadas, o .NET Aspire promove as melhores práticas ao fornecer uma política de resiliência padrão e sensata pronta para uso.
Principais Pontos:
- Falhas transitórias são comuns em sistemas distribuídos, e o padrão de repetição (Retry) é uma defesa de primeira linha contra elas.
- A biblioteca Polly, através do novo pacote
Microsoft.Extensions.Http.Resilience, é a maneira moderna de implementar resiliência no .NET. - Uma política de repetição eficaz usa backoff exponencial e jitter para evitar sobrecarregar os serviços dependentes.
- O .NET Aspire simplifica enormemente a resiliência ao aplicar o
AddStandardResilienceHandlerpor padrão a todos osHttpClients através do projetoServiceDefaults, garantindo que sua aplicação seja resiliente desde o início.
Próxima Lição:
Repetir indefinidamente uma chamada para um serviço que está completamente fora do ar não é apenas inútil, mas também prejudicial, pois consome recursos do serviço cliente. Para evitar isso, precisamos de um mecanismo que possa "abrir o circuito" e parar de enviar solicitações por um tempo. Na próxima lição, vamos explorar o padrão Circuit Breaker, a próxima camada em nossa estratégia de resiliência.