Implementar repetições de chamadas HTTP com retirada exponencial com o HttpClientFactory e as políticas do Polly

Dica

Esse conteúdo é um trecho do eBook da Arquitetura de Microsserviços do .NET para os Aplicativos .NET em Contêineres, disponível no .NET Docs ou como um PDF para download gratuito que pode ser lido offline.

.NET Microservices Architecture for Containerized .NET Applications eBook cover thumbnail.

A abordagem recomendada para repetições com retirada exponencial é aproveitar as bibliotecas do .NET mais avançadas como a biblioteca Polly de software livre.

A Polly é uma biblioteca .NET que fornece resiliência e recursos de tratamento de falhas temporárias. Você pode implementar essas funcionalidades por meio da aplicação de políticas da Polly como repetição, disjuntor, isolamento do bulkhead, tempo limite e fallback. O Polly é direcionado ao .NET Framework 4.x e ao .NET Standard 1.0, 1.1 e 2.0 (que dá suporte ao .NET Core e posteriores).

As etapas a seguir mostram como você pode usar as repetições HTTP com o Polly integrado ao IHttpClientFactory, o que foi explicado na seção anterior.

Instalar os pacotes do .NET

Primeiro, você precisará instalar o pacote Microsoft.Extensions.Http.Polly.

Fazer referência aos pacotes do .NET 8

O IHttpClientFactory está disponível desde o .NET Core 2.1, mas recomendamos o uso dos pacotes do .NET 8 mais recentes a partir do NuGet no seu projeto. Normalmente, você também precisa referenciar o pacote de extensão Microsoft.Extensions.Http.Polly.

Configurar um cliente com a política de repetição da Polly, na inicialização do aplicativo

O método AddPolicyHandler() é aquele que adiciona políticas aos objetos HttpClient que você usará. Nesse caso, ele está adicionando a política do Polly para repetições de HTTP com retirada exponencial.

Para obter uma abordagem mais modular, a política de repetição de Http pode ser definida em um método separado no arquivo Program.cs, como mostra o seguinte código:

static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
    return HttpPolicyExtensions
        .HandleTransientHttpError()
        .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
        .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2,
                                                                    retryAttempt)));
}

Conforme mostrado nas seções anteriores, você precisa definir uma configuração HttpClient de cliente nomeada ou tipada na configuração de aplicativos Program.cs padrão. Agora você adiciona código incremental especificando a política para as repetições Http com retirada exponencial, conforme a seguir:

// Program.cs
builder.Services.AddHttpClient<IBasketService, BasketService>()
        .SetHandlerLifetime(TimeSpan.FromMinutes(5))  //Set lifetime to five minutes
        .AddPolicyHandler(GetRetryPolicy());

Com a Polly, você pode definir uma política de repetição com o número de repetições, a configuração de retirada exponencial e as ações a serem executadas quando houver uma exceção de HTTP, como registrar o erro em log. Nesse caso, a política é configurada para tentar seis vezes com uma repetição exponencial, começando em dois segundos.

Adicionar uma estratégia de tremulação à política de repetição

Uma política de repetição regular pode afetar o sistema em casos de alta simultaneidade e escalabilidade e sob alta contenção. Para superar os picos de repetições semelhantes provenientes de muitos clientes em caso de interrupções parciais, uma boa solução alternativa é adicionar uma estratégia de variação à política ou ao algoritmo de repetição. Essa estratégia pode aprimorar o desempenho geral do sistema de ponta a ponta. Conforme recomendado em Polly: repetição com variação, uma boa estratégia de variação pode ser implementada por intervalos de repetição suaves e distribuídos uniformemente, aplicados com um atraso de repetição inicial mediano bem controlado em uma retirada exponencial. Essa abordagem ajuda a espalhar os picos quando o problema surge. O princípio é ilustrado pelo seguinte exemplo:


var delay = Backoff.DecorrelatedJitterBackoffV2(medianFirstRetryDelay: TimeSpan.FromSeconds(1), retryCount: 5);

var retryPolicy = Policy
    .Handle<FooException>()
    .WaitAndRetryAsync(delay);

Recursos adicionais