Implémenter des tentatives d’appel HTTP avec backoff exponentiel avec des stratégies IHttpClientFactory et Polly

Conseil

Ce contenu est un extrait du livre électronique « .NET Microservices Architecture for Containerized .NET Applications », disponible sur .NET Docs ou sous forme de PDF téléchargeable gratuitement et pouvant être lu hors ligne.

Image miniature de la couverture du livre électronique .NET Microservices Architecture for Containerized .NET Applications.

L’approche recommandée pour les nouvelles tentatives avec interruption exponentielle est d’utiliser des bibliothèques .NET plus avancées telles que la bibliothèque Polly open source.

Polly est une bibliothèque .NET qui fournit des fonctionnalités de résilience et de gestion des erreurs temporaires. Vous pouvez implémenter ces fonctionnalités en appliquant des stratégies Polly comme Retry (Nouvelle tentative), Circuit Breaker (Disjoncteur), Bulkhead Isolation (Isolation par cloisonnement), Timeout (Délai d’attente) et Fallback (Alternative de repli). Polly cible .NET Framework 4.x et .NET Standard 1.0, 1.1 et 2.0 (qui prend en charge .NET Core et versions ultérieures).

Les étapes suivantes montrent comment utiliser des nouvelles tentatives Http avec Polly intégrées à IHttpClientFactory, qui est expliquée dans la section précédente.

Référencer les packages .NET 7

IHttpClientFactory est disponible depuis .NET Core 2.1. Toutefois, nous vous recommandons d’utiliser les derniers packages .NET Core 7 à partir de NuGet dans votre projet. En règle générale, vous devez également référencer le package d’extension Microsoft.Extensions.Http.Polly.

Configurer un client avec la stratégie de nouvelle tentative de Polly, dans le démarrage des applications

Comme indiqué dans les sections précédentes, vous devez définir une configuration HttpClient cliente nommée ou typée dans votre configuration d’application Program.cs standard. Vous ajoutez maintenant du code incrémentiel en spécifiant la stratégie pour les nouvelles tentatives Http avec backoff exponentiel, comme ci-dessous :

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

La méthode AddPolicyHandler() ajoute des stratégies aux objets HttpClient que vous utiliserez. Dans ce cas, elle ajoute une stratégie de Polly pour les nouvelles tentatives Http avec backoff exponentiel.

Afin de bénéficier d’une approche plus modulaire, la stratégie de nouvelle tentative Http peut être définie dans une méthode distincte dans le fichier Program.cs, comme illustré par le code suivant :

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

Avec Polly, vous pouvez définir une stratégie Retry en spécifiant le nombre de nouvelles tentatives, la configuration de l’interruption exponentielle et les actions à effectuer quand une exception HTTP se produit (par exemple, journaliser l’erreur). Dans ce cas, la stratégie est configurée pour essayer six fois avec une nouvelle tentative exponentielle commençant à deux secondes.

Ajouter une stratégie d’instabilité à la stratégie de nouvelle tentative

Une stratégie de nouvelles tentatives régulière peut affecter votre système en cas de concurrence et de scalabilité élevée et en cas de conflit élevé. Pour surmonter les pics de nouvelles tentatives similaires provenant de nombreux clients en pannes partielles, une bonne solution de contournement consiste à ajouter une stratégie de gigue à l’algorithme/la stratégie de nouvelles tentatives. Cette stratégie peut améliorer les performances globales du système de bout en bout. Comme recommandé dans Polly : Réessayer avec Jitter, une bonne stratégie de gigue peut être implémentée par des intervalles de nouvelle tentative distribués en douceur et uniformément distribués appliqués avec un délai de nouvelle tentative médiane bien contrôlé sur un backoff exponentiel. Cette approche permet de répartir les pics lorsque le problème se produit. Le principe est illustré dans l’exemple suivant :


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

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

Ressources supplémentaires