Runtime: Singleton HttpClient ne respecte pas les modifications DNS

Créé le 29 août 2016  ·  77Commentaires  ·  Source: dotnet/runtime

Comme décrit dans l'article suivant : http://byterot.blogspot.co.uk/2016/07/singleton-httpclient-dns.html , une fois que vous commencez à conserver une instance partagée HttpClient pour améliorer les performances, vous Je rencontrerai un problème dans lequel le client ne respectera pas les mises à jour des enregistrements DNS en cas de scénarios de basculement.

Le problème sous-jacent est que la valeur par défaut de ConnectionLeaseTimeout est définie sur -1 , infinie. Il ne se fermera qu'à l'élimination du client, ce qui est très inefficace.

Le correctif consiste à mettre à jour la valeur sur le point de service comme ceci :

var sp = ServicePointManager.FindServicePoint(new Uri("http://foo.bar/baz/123?a=ab"));
sp.ConnectionLeaseTimeout = 60*1000; // 1 minute

Malheureusement, il n'y a aucun moyen de le faire avec .NET Core aujourd'hui.

Soit ServicePointManager doit être transféré vers .NET Core, soit une fonctionnalité équivalente similaire doit être activée d'une autre manière.

area-System.Net.Http enhancement

Commentaire le plus utile

C'est absolument un problème. La solution proposée par @darrelmiller semble démontrer un manque de compréhension du cas d'utilisation.

Nous utilisons Azure Traffic Managers pour évaluer la santé d'une instance. Ils fonctionnent au-dessus du DNS avec des TTL courts. Un hôte ne sait pas comme par magie qu'il est défectueux et commence à émettre Connection:close . Le gestionnaire de trafic détecte simplement l'état défectueux et ajuste la résolution DNS en conséquence. De par sa conception, cela est COMPLÈTEMENT TRANSPARENT pour les clients et les hôtes... dans l'état actuel des choses, une application avec un DNS statique HttpClient résolvant (inconsciemment) par un gestionnaire de trafic ne recevra jamais un nouvel hôte lorsque l'hôte précédemment résolu devient défectueux.

Depuis netcore 1.1, je suis actuellement à la recherche d'une solution à ce problème précis. Je n'en vois pas, natif en tout cas.

Tous les 77 commentaires

La valeur par défaut est de 60 secondes et vous pouvez le régler manuellement sur ce que vous voulez. https://github.com/dotnet/corefx/blob/d0dc5fc099946adc1035b34a8b1f6042eddb0c75/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs#L76

Je ne pense pas que ce soit la même propriété. C'est le délai d'expiration de la connexion, pas le ConnectionLeaseTimeout.

Comme documenté dans https://msdn.microsoft.com/en-us/library/system.net.servicepoint.connectionleasetimeout.aspx , il doit être supprimé périodiquement dans certains scénarios. Mais il n'y a aucun moyen apparent de modifier le comportement sur .NET Core.

@onovotny Oui, c'est une chose étrange qui semble établir une  : se fermer après un certain laps de temps. Il n'y a aucune raison qui ne pourrait pas être implémentée en tant qu'intergiciel si vous le vouliez vraiment. C'est juste un en-tête HTTP.

@darrelmiller donc ça sort de ma zone, pas sûr... mais s'il existe une solution de contournement documentée qui résout le problème d'origine, ce serait un énorme avantage.

@onovotny , il n'y a pas ServicePointManager classe

@onovotny Le problème d'origine, si je comprends bien, est que, côté serveur, quelqu'un souhaite mettre à jour une entrée DNS afin que toutes les futures demandes d'hébergement A aillent à une nouvelle adresse IP. La meilleure solution à mon avis est que lorsque cette entrée DNS est modifiée, l'application sur l'hôte A doit être invitée à renvoyer un en-tête Connection:close lorsque ce délai d'attente "de bail" expire.

Cela correspond bien à la question dans Stackoverflow Unit testant le basculement DNS, à l'aide d'un résolveur DNS personnalisé et peut donner un contexte supplémentaire autour de ce problème, donc je vais lier (je supprimerai ici si cela est inapproprié).

C'est absolument un problème. La solution proposée par @darrelmiller semble démontrer un manque de compréhension du cas d'utilisation.

Nous utilisons Azure Traffic Managers pour évaluer la santé d'une instance. Ils fonctionnent au-dessus du DNS avec des TTL courts. Un hôte ne sait pas comme par magie qu'il est défectueux et commence à émettre Connection:close . Le gestionnaire de trafic détecte simplement l'état défectueux et ajuste la résolution DNS en conséquence. De par sa conception, cela est COMPLÈTEMENT TRANSPARENT pour les clients et les hôtes... dans l'état actuel des choses, une application avec un DNS statique HttpClient résolvant (inconsciemment) par un gestionnaire de trafic ne recevra jamais un nouvel hôte lorsque l'hôte précédemment résolu devient défectueux.

Depuis netcore 1.1, je suis actuellement à la recherche d'une solution à ce problème précis. Je n'en vois pas, natif en tout cas.

@kudoz83 Vous avez raison, un hôte ne sait pas comme par magie quand un gestionnaire de trafic a ajusté la résolution DNS, c'est pourquoi j'ai dit

lorsque cette entrée DNS est modifiée, l'application sur l'hôte A doit être informée

Si vous ne pensez pas qu'il soit pratique d'informer un serveur d'origine qu'il doit renvoyer les en-têtes connection:close, il ne vous reste que quelques choix :

  • Fermez périodiquement les connexions d'un client ou d'un middleware et payez le coût de la réouverture de ces connexions de manière redondante
  • Demandez au client d'interroger un service pour savoir quand il doit réinitialiser les connexions.
  • Utilisez un middleware suffisamment intelligent pour savoir quand le DNS a été basculé.

Et en ce qui me concerne, je ne comprends pas le cas d'utilisation. Le problème d'origine était basé sur un article de blog où le cas d'utilisation était lié au basculement entre les créneaux de production et de mise en scène et n'avait rien à voir avec la surveillance de la santé. Bien que les deux scénarios puissent bénéficier de la possibilité de recevoir des notifications de commutateurs DNS/slot.

AFAIK, il n'y a pas de moyen d'informer un hôte défaillant qu'il est défaillant ? En général, cela signifie qu'il est dans une sorte d'état d'erreur. Le message d'origine parle de scénarios de basculement.

Azure Traffic Manager est expliqué ici https://docs.microsoft.com/en-us/azure/traffic-manager/traffic-manager-monitoring

Il fonctionne au niveau DNS et est transparent pour les clients et les hôtes - par conception. Les instances Azure communiquant entre elles via Traffic Manager pour la résolution DNS sont en difficulté sans pouvoir définir une durée de vie sur l'actualisation DNS pour un HttpClient.

La façon dont HttpClient fonctionne actuellement semble être en contradiction avec les propres offres de services Azure de Microsoft - ce qui est tout l'essentiel. Sans oublier que tout service similaire (par exemple Amazon Route 53) fonctionne exactement de la même manière et a exactement la même dépendance DNS TTL courte.

Évidemment, j'ai trouvé ce fil parce que je suis touché par le problème. J'essaie simplement de préciser qu'il ne semble pas exister de solution de contournement idéale actuellement, à part simplement recréer arbitrairement des HttpClients (au détriment des performances et de la complexité) pour garantir la réussite du basculement DNS.

AFAIK, il n'y a pas de moyen d'informer un hôte défaillant qu'il est défaillant ?

Si un hôte "en échec" ne pouvait exécuter aucun code, nous n'aurions pas besoin du code d'état HTTP 503 car un serveur d'origine ne serait jamais capable de le renvoyer. Il existe des scénarios où un hôte défaillant peut ne pas être capable de traiter une notification, mais dans ces cas, il ne maintiendra probablement pas non plus une connexion TCP/IP active ouverte très longtemps.

Lorsqu'Ali a initialement abordé ce sujet sur Twitter, avant d'écrire le billet de blog, il s'était entendu sur le fait qu'un client continuerait à faire des demandes et à obtenir des réponses d'un serveur qui avait été échangé.

Je comprends que votre situation est différente et que vous ne pouvez pas compter sur un serveur d'origine capable de fermer une connexion de manière fiable. Ce que je ne suis pas sûr de comprendre, c'est pourquoi, dans votre situation, vous ne pouvez pas utiliser un HttpMessageHandler pour détecter les réponses 5XX, fermer la connexion et réessayer la demande. Ou encore plus simple, il suffit de convaincre votre serveur Web de renvoyer la connexion : fermez chaque fois qu'il renvoie un code d'état 5XX.

Il convient également de noter que le comportement qui vous intéresse n'est pas dans HttpClient. Il se trouve dans le HttpHandler sous-jacent ou même en dessous, et il existe un certain nombre d'implémentations différentes de HttpHandler en cours d'utilisation. À mon avis, le comportement actuel est cohérent avec la façon dont HTTP est conçu pour fonctionner. Je suis d'accord qu'il y a un défi lorsque les paramètres DNS sont mis à jour alors que les connexions sont ouvertes, mais ce n'est pas un problème .net. Il s'agit d'un problème d'architecture HTTP. Cela ne veut pas dire que .net ne pouvait pas faire quelque chose pour rendre cela moins problématique.

Je suis curieux de savoir quelle devrait être la solution selon vous. Pensez-vous que quelque chose comme le ConnectionLeaseTimeout devrait être réimplémenté pour simplement supprimer une connexion périodiquement, qu'il y ait eu un basculement ou non ? Ou avez-vous une meilleure solution?

Pardon,

Je n'aurais pas dû paraître aussi combatif qu'hier. Passait une mauvaise journée.

Honnêtement, je ne sais pas comment fonctionne ConnectionLeaseTimeout sous les couvertures. La fonctionnalité souhaitée serait que HttpClient soit configurable afin d'effectuer une nouvelle recherche DNS, avant d'établir de nouvelles connexions, par opposition à la mise en cache de la recherche DNS précédente jusqu'à ce que le client soit supprimé. Je ne crois pas que cela nécessite de tuer une connexion existante...

@kudoz83 Pas de soucis, on a tous des jours comme ça :-)

D'après ce que je comprends, ConnectionLeaseTimeout est littéralement une minuterie qui ferme périodiquement une connexion inactive du côté client. Il est implémenté dans ServicePointManager, qui n'existe pas dans le noyau. Ceci est différent du délai d'attente de "connexion inactive" qui ne ferme une connexion qu'une fois qu'elle n'a pas été utilisée pendant une certaine période de temps.

Il existe probablement un appel Win32 qui permettrait de vider le cache du client DNS. Cela garantirait que les nouvelles connexions effectuent une recherche DNS. Je l'ai cherché rapidement mais je ne l'ai pas trouvé, mais je suis sûr qu'il est là quelque part.

Dans le noyau .net sous Windows, la gestion des connexions HTTP est en fait laissée à l'OS. Le plus proche que vous obtenez est l'appel à l'API Win32 WinHttpOpen https://github.com/dotnet/corefx/blob/master/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs# L718 Il n'y a pas d'API publiques que je puisse trouver pour faire quoi que ce soit avec le _sessionHandle. Pour obtenir le type de changement de comportement que vous recherchez, les utilisateurs du système d'exploitation devraient apporter des modifications. Du moins c'est comme ça que je le comprends.

Ne serait-il pas plus facile d'obtenir Azure Traffic Manager simplement pour définir un TTL très faible sur les entrées DNS ? Si vous n'êtes pas préoccupé par les connexions de longue durée, un faible TTL devrait minimiser les risques de configuration de nouvelles connexions contre un serveur mort.

L'avantage de la façon dont WinHttpHandler est construit est que nous obtenons des choses comme HTTP/2 gratuitement avec la mise à jour du système d'exploitation. L'inconvénient est que nous n'avons pas beaucoup de contrôle sur le code managé.

@darrelmiller

[ConnectionLeaseTimeout] est implémenté dans ServicePointManager, qui n'existe pas dans le noyau.

Il semble que ServicePoint.ConnectionLeaseTimeout revienne dans .Net Standard 2.0/.Net Core 1.2. (Bien que je ne sache pas si, par exemple, les connexions WinHttpHandler y adhéreront.)

Je pense qu'il y a un malentendu ici : les DNS TTL ne sont absolument pas liés à la durée de vie des connexions HTTP/TCP.

Les nouvelles connexions HTTP effectuent une recherche DNS et se connectent à l'adresse hôte renvoyée. Plusieurs requêtes HTTP peuvent être effectuées sur la même connexion, mais une fois ouverte, la connexion HTTP (et la connexion TCP sous-jacente) ne fait plus de recherche DNS.

C'est un comportement correct, donc même si vous effectuez des milliers de requêtes sur une connexion qui dure des jours, la résolution DNS n'a pas d'importance puisque la connexion n'a pas changé. Si vous effectuez une nouvelle requête HTTP via une nouvelle connexion HTTP, vous verrez une recherche DNS pour la nouvelle connexion.

Cette actualisation DNS n'a rien à voir avec HttpClient , qui utilise simplement HttpClientHandler par défaut (qui utilise lui-même la pile de sockets HttpWebRequest ) et toute résolution DNS est gérée par cette pile. ServicePointManager gère les objets ServicePoint dans cette pile qui sont des connexions à un hôte spécifique. ServicePointManager a une certaine mise en cache côté client minimum de recherche DNS que vous pouvez modifier.

Les paramètres par défaut sont conçus pour que les connexions restent ouvertes indéfiniment pour plus d'efficacité. Si l'hôte connecté devient indisponible, la connexion sera automatiquement interrompue, provoquant une nouvelle connexion avec une nouvelle recherche DNS, mais les TTL DNS ne provoqueront aucune nouvelle connexion. Si vous en avez besoin, vous devrez le coder dans votre application.

Si vous souhaitez effectuer une autre recherche DNS, vous devez réinitialiser la connexion sur le client. Vous pouvez forcer une durée de vie maximale de la connexion TCP, envoyer un en-tête connection: close ou simplement disposer le HttpClient ou le sous-jacent ServicePoint . Vous pouvez également effectuer la résolution DNS avec Dns.GetHostAddresses et utiliser l'adresse IP à la place pour vos requêtes HTTP.

J'espère que cela vous aidera, si je ne suis pas sur ce sujet, faites-le moi savoir.

@manigandham

Je pense qu'il y a un malentendu ici : les DNS TTL ne sont absolument pas liés à la durée de vie des connexions HTTP/TCP.

Oui, les DNS TTL sont assez indépendants, mais pas complètement.

Les nouvelles connexions HTTP effectuent une recherche DNS et se connectent à l'adresse hôte renvoyée.

Oui c'est correct. Mais Windows dispose d'un cache DNS local qui respecte le TTL. Si la durée de vie est élevée et que le serveur DNS a modifié l'enregistrement DNS, la nouvelle connexion sera ouverte par rapport à l'ancienne adresse IP en raison de la mise en cache client de l'enregistrement DNS. Le vidage du cache DNS du client est la seule solution de contournement à ma connaissance.

Plusieurs requêtes HTTP peuvent être effectuées sur la même connexion, mais une fois ouverte, la connexion HTTP (et la connexion TCP sous-jacente) ne fait plus de recherche DNS.

Corrigez à nouveau. Dans un échange de production/mise en scène où le serveur échangé répond toujours, cela entraînera l'envoi de nombreuses demandes futures vers l'ancien serveur, ce qui est mauvais. Cependant, la conversation la plus récente a porté sur le scénario dans lequel un serveur tombe en panne et le Traffic Manager passe à un nouveau serveur. Ce qui arrive à la connexion existante au serveur défaillant est inconnu. S'il s'agit d'une panne matérielle grave, il y a de fortes chances que la connexion soit interrompue. Cela forcerait le client à rétablir une connexion et c'est là qu'un faible TTL est utile. Si toutefois, la défaillance du serveur ne brise pas le serveur et qu'il renvoie simplement des réponses 5XX, il serait alors utile que le serveur renvoie la connexion:close pour s'assurer que les futures demandes seront effectuées sur une nouvelle connexion, espérons-le sur le nouveau fonctionnement serveur

Ce rafraîchissement DNS n'a rien à voir avec HttpClient, qui utilise simplement HttpClientHandler par défaut (qui utilise lui-même la pile de sockets HttpWebRequest)

Oui et non. Sur le noyau .Net, le HttpClientHandler a été réécrit et n'utilise plus HttpWebRequest et n'utilise donc pas ServicePointManager. D'où la raison de ce problème.

J'ai examiné de plus près IIS et il ne semble pas y avoir de moyen d'obtenir des réponses 5XX avec les en-têtes connection:close . Il serait nécessaire d'implémenter un HttpModule pour faire cette magie.

En tant que FYI, voici un article connexe couvrant ce problème et une solution provisoire. Méfiez-vous de HttpClient

Soit ServicePointManager doit être transféré vers .NET Core

Bien que nous ayons apporté ServicePointManager et HttpWebRequest pour la parité de plate-forme, il ne prend pas en charge la plupart des fonctionnalités de .Net Core car la pile sous-jacente se résout en WinHTTP ou en Curl qui n'exposent pas les boutons de contrôle avancés.

L'utilisation de ServicePointManager pour contrôler HttpClient est en fait un effet secondaire de l'utilisation de HttpWebRequest et de la pile HTTP gérée sur .Net Framework. Étant donné que WinHttpHandler/CurlHandler sont utilisés sur .Net Core, SPM n'a aucun contrôle sur les instances HttpClient.

ou une fonctionnalité équivalente similaire doit être activée d'une autre manière.

Voici la réponse de l'équipe WinHTTP :

  1. Pour des raisons de sécurité, tant que le client continue d'envoyer des demandes et qu'il existe des connexions actives, WinHTTP continuera à utiliser l'adresse IP de destination. Il n'y a aucun moyen de limiter la durée pendant laquelle ces connexions restent actives.
  2. Si toutes les connexions au point de terminaison distant ont été fermées par le serveur, de _nouvelles_ connexions seront effectuées en interrogeant DNS et donc vers la nouvelle IP.

Pour forcer les clients à passer à l'adresse IP suivante, la seule solution viable est de s'assurer que le serveur rejette les nouvelles connexions et ferme celles existantes (déjà mentionnées sur ce fil).
C'est la même chose avec ce que j'ai compris de la documentation ATM : la détection est faite sur la base des requêtes GET qui échouent 4 fois (réponses non-200) auquel cas les connexions seront fermées par le serveur.

Étant donné que d'autres appareils réseau mettent eux-mêmes en cache le DNS (par exemple, les routeurs/points d'accès domestiques), je ne recommanderais pas le basculement DNS comme solution pour une technique à faible latence et haute disponibilité. Si cela est nécessaire, ma recommandation pour un basculement contrôlé serait d'avoir un LB dédié (matériel ou logiciel) qui sait comment s'arrêter correctement.

dans l'état actuel des choses, une application avec un HttpClient statique résolvant le DNS (inconsciemment) par un gestionnaire de trafic ne recevra jamais un nouvel hôte lorsque l'hôte précédemment résolu devient défectueux.

Comme mentionné ci-dessus, si par malsain vous entendez que le serveur renvoie un code d'erreur HTTP et ferme la connexion TCP pendant que vous observez le DNS TTL expiré, il s'agit bien d'un bug.

Veuillez décrire votre scénario plus en détail :

  1. Pendant le basculement, quel est le cache DNS et les TTL de la machine cliente. Vous pouvez utiliser ipconfig /showdns et nslookup -type=soa <domain_name> pour comparer ce que la machine pense être le TTL et les TTL du NS faisant autorité.
  2. Existe-t-il des connexions actives vers le serveur distant ? Vous pouvez utiliser netstat /a /n /b pour voir les connexions et les processus qui les possèdent.
  3. La création d'une reproduction nous aiderait beaucoup : veuillez joindre toutes les informations disponibles telles que : version de .Net Core/Framework, code pour client/serveur, traces réseau, DNS LB/Traffic Manager distant impliqué, etc.

Si vous vous connectez à une machine et que la connexion TCP/HTTP continue de fonctionner, pourquoi devriez-vous à un moment donné supposer que le serveur n'est plus approprié.
Je pense qu'il y a place à amélioration du côté d'Azure. Par exemple, lorsque les machines sont malsaines ou échangent des environnements, les connexions existantes peuvent être fermées.

ou simplement disposer du ... ServicePoint sous-jacent

@manigandham Comment ? Ce n'est pas jetable et la seule méthode pertinente que je peux voir est CloseConnectionGroup que vous ne pouvez pas vraiment utiliser car le nom du groupe est un détail d'implémentation (actuellement un hachage du gestionnaire). De plus, je ne sais pas ce qui se passerait si vous essayiez de supprimer le ServicePoint pendant que le HttpClient utilisait (surtout en même temps).

@ohadschn

.NET Core 2.0 ramène les classes et fonctionnalités ServicePoint : https://docs.microsoft.com/en-us/dotnet/api/system.net.servicepoint?view=netcore-2.0

Vous pouvez revenir à l'utilisation du délai d'expiration du bail de connexion pour définir un délai maximal pour les connexions actives avant qu'elles ne soient réinitialisées.

Rien d'exotique à fermer la connexion alors que la demande de HttpClient est en cours, ce serait la même chose que de perdre la connectivité lors de la navigation sur Internet. Soit la demande ne le fait jamais, soit elle le fait et vous n'obtenez pas de réponse - les deux devraient conduire à des erreurs http renvoyées et vous devrez les gérer dans votre application.

Avec le paramètre de délai d'expiration du bail de connexion, vous pouvez vous assurer que cela n'est effectué qu'après l'envoi d'une demande et qu'il est réinitialisé avant la suivante au-delà de la limite de temps.

.NET Core 2.0 ramène les classes et fonctionnalités ServicePoint : https://docs.microsoft.com/en-us/dotnet/api/system.net.servicepoint?view=netcore-2.0
Vous pouvez revenir à l'utilisation du délai d'expiration du bail de connexion pour définir un délai maximal pour les connexions actives avant qu'elles ne soient réinitialisées.

En fait, cela ne ramène pas complètement la fonctionnalité. La surface de l'API est revenue. Mais c'est fondamentalement un no-op puisque les piles HTTP n'utilisent pas ce modèle d'objet.

cc : @stephentoub @geoffkizer

Je considérerais de nombreux participants à ce fil comme une "équipe de rêve" sur ce sujet, mais je ne suis toujours pas sûr qu'un consensus ait été atteint sur les meilleures pratiques étant donné ce que nous avons aujourd'hui. Ce serait formidable d'obtenir une réponse décisive de ce groupe sur quelques points clés.

Disons que j'ai une bibliothèque HTTP à usage général ciblant de nombreuses plates-formes, qui ne prennent pas toutes en charge ServicePointManager , et j'essaie de fournir un comportement qui gère intelligemment les instances HttpClient , selon les meilleures pratiques, par défaut. Je n'ai aucune idée à l'avance de ce que les hôtes seront appelés, et encore moins s'ils se comportent bien en ce qui concerne les modifications DNS/C onnexion : fermer les en- têtes.

  1. Comment gérer de manière optimale les instances HttpClient ? Un par point de terminaison ? Un par hôte/schéma/port ? Littéralement un singleton au total ? (J'en doute, car les consommateurs peuvent vouloir profiter des en-têtes par défaut, etc.)

  2. Comment pourrais-je traiter le plus efficacement ce problème DNS ? Supprimer les instances après 1 minute ? Traitez-le comme « hautement improbable » et ne fournissez aucun comportement d'élimination par défaut ?

(Ce n'est pas une situation hypothétique d'ailleurs ; je me bats avec ces questions exactes en ce moment.)

Merci!

Je ne serais même pas invité aux essais de l'équipe de rêve, mais j'ai un aperçu de votre commentaire sur le singleton HttpClient . Tout d'abord, vous pouvez toujours utiliser la méthode SendAsync pour spécifier différents en-têtes et adresses, vous pouvez donc les envelopper avec votre classe qui fournit des données partagées similaires à HttpClient (par exemple, en-têtes par défaut, adresse de base) finit par appeler le même client unique. Mais encore mieux, vous pouvez créer plusieurs instances HttpClient qui partagent toutes le même HttpClientHandler : https://github.com/dotnet/corefx/issues/5811.

En ce qui concerne la question DNS, le consensus semble ici être que :

Pour forcer les clients à passer à l'adresse IP suivante, la seule solution viable consiste à s'assurer que le serveur rejette les nouvelles connexions et ferme celles existantes

Si cela n'est pas viable pour vous, Darrel Miller a suggéré d'autres options ici : https://github.com/dotnet/corefx/issues/11224#issuecomment -270498159.

@ohadschn Merci, et j'espère que je ne

En ce qui concerne les conseils DNS, j'avais l'impression que c'était là où le consensus manquait le plus, et c'est compréhensible. S'assurer que le serveur se comporte correctement n'est pas viable si vous n'avez pas le contrôle de ce qui se passe à cette extrémité. Je _pourrais_ concevoir quelque chose où les instances sont éliminées périodiquement. La question est de savoir si cela vaut le compromis dans la majorité des cas. Je suppose que c'est en grande partie à moi de porter un jugement. :)

Pour moi, l'avantage le plus évident de partager le même HttpClient [ Handler ] est la simplicité. Vous n'aurez pas à conserver des éléments tels que le mappage entre les hôtes et les clients. Je ne connais pas les trucs TIME_WAIT, vraiment pas mon expertise non plus.

Concernant le DNS, vous avez évoqué une approche possible lorsque vous ne contrôlez pas le serveur. Vous pouvez également implémenter un mécanisme qui interroge périodiquement le DNS et supprime les instances uniquement si un changement réel s'est produit...

Alors que les réponses données qui spécifient ce qui doit se passer côté serveur sont exactes pour un monde idéal, dans le monde réel, les développeurs n'ont souvent pas le contrôle de la pile côté serveur complète avec laquelle ils communiquent. À cet égard, j'aime beaucoup le concept d'un ConnectionLeaseTimeout, car c'est une concession aux réalités de la vie quotidienne de John et Jane Doeveloper.
Quelqu'un a suggéré d'écrire un middleware pour appliquer un tel délai d'attente sur .NET Core. Cette classe basée sur NodaTime et System.Collections.Immutable ferait-elle le travail ?

    public class ConnectionLeaseTimeoutHandler : DelegatingHandler
    {
        private static string GetConnectionKey(Uri requestUri) => $"{requestUri.Scheme}://{requestUri.Host}:{requestUri.Port}";

        private readonly IClock clock;
        private readonly Duration leaseTimeout;
        private ImmutableDictionary<string, Instant> connectionLeases = ImmutableDictionary<string, Instant>.Empty;

        public ConnectionLeaseTimeoutHandler(HttpMessageHandler innerHandler, IClock clock, Duration leaseTimeout)
            : base(innerHandler)
        {
            this.clock = clock;
            this.leaseTimeout = leaseTimeout;
        }

        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            string key = GetConnectionKey(request.RequestUri);
            Instant now = clock.GetCurrentInstant();

            Instant leaseStart = ImmutableInterlocked.GetOrAdd(ref connectionLeases, key, now);

            if (now - leaseStart > leaseTimeout)
            {
                request.Headers.ConnectionClose = true;
                ImmutableInterlocked.TryRemove(ref connectionLeases, key, out leaseStart);
            }

            return base.SendAsync(request, cancellationToken);
        }
    }

@snboisen Je pense que ça a l'air bien mais ne m'y tenez pas. :)

Pour moi, la plus grande question est de savoir si l'envoi d'un en-tête Connection: close est même une solution viable. Cela vaut la peine de répéter ici ce que @darrelmiller a dit dans les commentaires du billet de blog qui a suscité ce fil :

ConnectionLeaseTimeout est une bête étrange, dont je n'étais pas au courant jusqu'à ce qu'Oren en parle aujourd'hui. Cela entraînera l' inclusion d'en- têtes aura envoyé sa réponse. Il est logique que cela soit défini sur infini par défaut, car c'est une manière étrange de forcer la fermeture des connexions lorsqu'un client effectue activement des demandes.

Je respecte l'opinion de Darrel et cela donne l'impression que toute cette approche est plutôt bidon. D'un autre côté, je suis d'accord sur le fait que que doit faire un développeur qui n'a pas le contrôle de ce qui se passe côté serveur ? Si cela fonctionne _parfois_, c'est peut-être la meilleure option que nous ayons ? C'est certainement "moins cher" que de supprimer périodiquement des HttpClients ou d'effectuer périodiquement des recherches DSN.

Existe-t-il un ticket Azure ouvert pour ce problème ?
De mon point de vue, il semble que vous essayez tous de contourner la façon dont cela est implémenté dans le gestionnaire de trafic d'Azure.
Je ne suis pas un utilisateur Azure, donc je le regarde de loin, me sentant moins enclin à sauter à travers ses cerceaux.

@tmds Je

@snboisen Êtes-vous en train de dire

@tmds Pour AWS, oui, au moins pour le basculement : https://aws.amazon.com/route53/faqs/#adjust_ttl_to_use_failover
Je ne connais pas d'autres fournisseurs de cloud, mais il semble probable que certains le fassent aussi.

@tmds Pour AWS, oui, au moins pour le basculement : https://aws.amazon.com/route53/faqs/#adjust_ttl_to_use_failover
Je ne connais pas d'autres fournisseurs de cloud, mais il semble probable que certains le fassent aussi.

Il y a deux scénarios problématiques ici :

  • le client est connecté à un serveur qui n'est plus là
  • le client est connecté à un serveur qui exécute maintenant une version obsolète du logiciel

Le basculement DNS est lié au premier. Il convient de supprimer les serveurs inaccessibles du DNS (dans AWS, Azure, ...).
La bonne façon de le détecter chez le client est un mécanisme de délai d'attente. Je ne sais pas s'il existe une telle propriété sur HttpClient (délai de réponse maximal sur une connexion établie).
Au niveau du protocole, les nouveaux protocoles websocket et http2 définissent des messages ping/pong pour vérifier la vivacité de la connexion.

Quand je propose d'ouvrir un ticket avec Azure, c'est pour le deuxième scénario.
Il n'y a aucune raison pour qu'un client ferme une connexion qui fonctionne. Si le serveur n'est plus approprié, les clients doivent être déconnectés et le serveur doit être rendu inaccessible.
J'ai trouvé un bon document sur les déploiements AWS Blue/Green : https://d0.awsstatic.com/whitepapers/AWS_Blue_Green_Deployments.pdf.
Il énumère plusieurs techniques. Pour ceux qui utilisent DNS, il mentionne _les complexités DNS TTL_. Pour ceux qui utilisent un équilibreur de charge _pas de complexité DNS_.

@tmds Merci pour le lien, c'est très intéressant.

Je me demande à quel point il est courant de s'appuyer sur DNS TTL plutôt que d'utiliser un équilibreur de charge. Ce dernier semble être une solution beaucoup plus fiable en général.

A connu un comportement similaire lors de l'utilisation de 2 applications API différentes dans Azure App Services qui communiquaient via HttpClient . Nous avons remarqué environ 250 requêtes dans nos tests de charge, nous commencions à avoir des délais d'attente et "Une connexion n'a pas pu être établie" HttpRequestException - Peu importait qu'il s'agisse d'utilisateurs simultanés ou de requêtes séquentielles.

Lorsque nous sommes passés à un bloc using pour nous assurer que les HttpClient sont éliminés dans chaque requête, nous n'avons reçu aucune de ces exceptions. L'impact sur les performances, le cas échéant, était négligeable d'un singleton à la syntaxe using .

Lorsque nous sommes passés à un bloc using pour nous assurer que les HttpClient sont éliminés dans chaque requête, nous n'avons reçu aucune de ces exceptions. L'impact sur les performances, le cas échéant, était négligeable d'un singleton à la syntaxe using .

Il ne s'agit pas nécessairement de performances, il s'agit de ne pas fuir les connexions TCP et d'obtenir des SocketException s.

Depuis MSDN :

HttpClient est destiné à être instancié une seule fois et réutilisé tout au long de la vie d'une application. Surtout dans les applications serveur, la création d'une nouvelle instance HttpClient pour chaque requête épuisera le nombre de sockets disponibles sous de fortes charges. Cela entraînera des erreurs SocketException .

Voir également https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

@khellang Merci pour le lien (et la clarification sur les SocketException s, j'ai certainement eu un malentendu là-bas) - J'ai rencontré ce message et 3 ou 4 autres messages décrivant exactement la même chose.

Je comprends qu'une instanciation unique est l'intention, mais lorsque nous l'utilisons dans Azure App Services, nous atteignons systématiquement HttpRequestExceptions sous une charge assez modeste (mentionné ci-dessus, 250 requêtes séquentielles). À moins qu'il n'existe une autre solution, l'élimination des HttpClient est la solution de contournement que nous avons dû implémenter afin d'éviter de rencontrer ces exceptions cohérentes.

Je suppose qu'une solution "plus correcte" consisterait à intercepter ces exceptions, à annuler toutes les demandes en attente, à éliminer explicitement le HttpClient , à ré-instancier le HttpClient et à réessayer toutes les demandes.

Cela semble être un peu le bordel pour quelque chose qui

est destiné à être instancié une fois et réutilisé tout au long de la vie de l'application

Nous aimerions une solution plus propre, mais il semble que ce ne soit pas quelque chose qui ne va pas avec notre code, mais plutôt une limitation avec le framework. Je suis plus qu'heureux de me tromper, j'ai juste besoin de quelques conseils sur la façon dont nous pouvons l'utiliser comme prévu et ne pas rencontrer ces problèmes.

@snboisen J'ai testé votre ConnectionLeaseTimeoutHandler et je trouve qu'il ne fonctionne pas avec plusieurs connexions. Une "fermeture" est émise pour une seule connexion à chaque fois que le délai d'expiration du bail se produit, mais plusieurs connexions peuvent être ouvertes avec une seule instance HttpClient lors de l'envoi de demandes en parallèle. D'après ce que je vois dans fiddler (j'utilise une mauvaise adresse IP pour générer des erreurs pour vérifier le commutateur DNS) après l'envoi de "close", certaines demandes utilisent la nouvelle IP et certaines demandes utilisent l'ancienne IP. Dans mon cas, j'ai une limite de connexion de 2 et il faut plusieurs itérations du délai d'expiration du bail de connexion pour actualiser les deux connexions. Ce serait évidemment bien pire avec plus de connexions simultanées à partir d'un serveur de production, mais cela finirait probablement par basculer après un certain temps.

Je ne connais pas de moyen d'émettre "près" de chaque connexion individuelle utilisée par une instance HttpClient. Ce serait certainement l'idéal, mais ce que je vais faire, c'est utiliser une méthode d'usine GetOrCreate() pour HttpClient et créer une nouvelle instance HttpClient toutes les 120 secondes pour garantir que toutes les nouvelles connexions sont créées. Je ne sais tout simplement pas comment procéder pour éliminer l'ancienne instance HttpClient une fois que toutes les demandes sont terminées pour fermer les connexions, mais je pense que .NET s'en occupe car cela n'a jamais été un problème de créer une nouvelle instance HttpClient par demande.

En passant, je pense que l'actualisation doit se produire sur le client. Le serveur ne peut être responsable de la communication des modifications DNS ni d'aucun middleware. Le but du DNS est de compenser une telle responsabilité afin que vous puissiez changer d'adresse IP à tout moment sans coordination entre un client et un serveur et pas seulement pour fournir un nom convivial pour une adresse IP. Le cas d'utilisation parfait est une adresse IP AWS Elastic. Le changement n'est reflété que dans le DNS. AWS ne saura pas envoyer des en-têtes "fermés" à partir de votre serveur Web s'exécutant sur une instance ec2. AWS ne sera pas au courant de chaque serveur Web reposant sur une instance ec2 qu'il gère. Le scénario pour l'ancien serveur qui n'envoie pas sur un en-tête "fermé" est un nouveau déploiement de serveur où exactement le même logiciel est déployé sur un nouveau serveur avec tout le trafic basculé par DNS. Rien ne devrait changer sur l'ancien serveur, surtout si vous devez revenir en arrière. Tout doit être modifié en douceur au même endroit avec DNS.

Quels que soient les problèmes plus importants abordés ici, ConnectionLeaseTimeout est-il désormais implémenté dans le noyau ? Et si oui, pourquoi ce problème n'est-il pas clos ? J'ai pu coder un exemple exactement comme le message d'origine sans aucun problème pour le moment. Que cela résolve ou non mes problèmes de connexion DNS, il _semble_ que ConnectionLeaseTimeout _est_ implémenté dans le noyau.

ServicePointMananager.ConnectionLeaseTimeout n'est pas implémenté dans .NET Core. L'utilisation de cette propriété dans .NET Core est un no-op. Il n'est fonctionnel que dans .NET Framework. Et par défaut, cette propriété est définie sur "off" dans .NET Framework.

Je comprends qu'une seule instanciation est l'intention, mais lorsque nous l'utilisons dans Azure App Services, nous atteignons systématiquement HttpRequestExceptions sous une charge assez modeste (mentionnée ci-dessus, 250 requêtes séquentielles). À moins qu'il n'existe une autre solution, la suppression du HttpClient est la solution de contournement que nous avons dû implémenter afin d'éviter de rencontrer ces exceptions cohérentes.

Nous avons réussi à remédier au problème d'épuisement des sockets en enveloppant HttpClient dans une API personnalisée qui permet à chaque requête http dans une application de réutiliser la même instance HttpClient (elle fait plus que cela , comme RestSharp mais c'est aussi l'un des avantages). La récupération est derrière un lock{} car toutes les 60 minutes, nous créons un nouveau HttpClient et le renvoyons à la place. Cela nous a permis de faire des requêtes http à grand volume à partir de notre application Web (en raison des intégrations lourdes que nous avons) tout en ne réutilisant toujours pas les anciennes connexions qui n'ont pas été fermées. Nous le faisons depuis environ un an maintenant avec succès (après avoir rencontré les problèmes d'épuisement des sockets).

Je suis sûr qu'il y a encore des implications en termes de performances (en particulier en raison de tout le verrouillage), mais c'est mieux que tout ce qui meurt à cause de l'épuisement des sockets.

@KallDrexx pourquoi avez-vous besoin de verrouiller l'instance « globale » ? Naïvement, je le stockerais en statique et je le remplacerais toutes les 60 minutes par un nouveau. Cela ne suffirait-il pas ?

Notre code pour obtenir un HttpClient est :

```c#
var timeSinceCreated = DateTime.UtcNow - _lastCreatedAt;
if (timeSinceCreated.TotalSeconds > SecondsToRecreateClient)
{
serrure (cadenas)
{
timeSinceCreated = DateTime.UtcNow - _lastCreatedAt;
if (timeSinceCreated.TotalSeconds > SecondsToRecreateClient)
{
_currentClient = new HttpClient();
_lastCreatedAt = DateTime.UtcNow;
}
}
}

        return _currentClient;

```

Je suppose donc que le verrouillage ne se produit qu'une fois par minute afin que plusieurs threads n'essayent pas de créer un nouveau HttpApiClient simultanément. Je pensais que nous bloquions plus agressivement.

Je vois, c'est donc une raison de commodité.
Alternativement, vous pouvez soit utiliser une mise à jour basée sur le minuteur (async), soit autoriser la création de plusieurs d'entre eux en parallèle (style d'initialisation paresseux non sécurisé), ou utiliser un mécanisme de synchronisation différent et ne pas bloquer les autres threads pendant le temps de création (ils pourrait réutiliser l'ancien).

Je vois, c'est donc une raison de commodité.

Je ne sais pas si je le classerais comme une commodité.

Si trop de threads essaient de créer un nouveau HttpClient en même temps, nous risquons toujours d'épuiser les sockets à cause d'un trop grand nombre de threads créés chaque minute, surtout si les anciens n'ont pas nettoyé correctement les sockets au cours de cette minute (provoquant une cascade).

De plus, j'aurais toujours besoin d'une mesure de verrouillage car je ne sais pas si la mise à jour d'un DateTime est une opération atomique (je suppose que non) et donc certains threads peuvent lire la _lastCreatedAt dans au milieu d'une opération de mise à jour.

Et pour que tous les threads réutilisent l'ancien client tout en ayant simultanément un thread pour créer un nouveau client, il faut beaucoup de logique complexe, nous sommes donc assurés qu'un thread crée avec succès le nouveau client. Sans oublier que nous avons toujours besoin de verrous car nous ne pouvons pas garantir qu'un thread ne retournera pas _currentClient pendant qu'un autre thread l'instancie.

Il y a beaucoup trop d'inconnues et de complexité supplémentaire pour risquer de le faire en production.

@KallDrexx

  • Il semble que ReaderWriterLockSlim conviendrait mieux à votre utilisation.
  • DateTime affectation de true x64 (car elle contient un seul champ ulong ). Notez que votre code actuel n'est pas thread-safe si ce n'est pas le cas, car vous observez la DateTime dehors du verrou.
  • L'approche basée sur la minuterie suggérée par @karelz ne nécessitera pas du tout un DateTime ... la minuterie changerait simplement le HttpClient . Vous auriez toujours besoin d'entourer le champ HttpClient avec une barrière mémoire ( volatile , Interlocked.Exchange etc).

Il semble que ReaderWriterLockSlim conviendrait mieux à votre utilisation.

Super, je ne connaissais pas ce cours ! Cependant, le fait que vous mentionniez cela m'a également fait penser à utiliser un SemaphoreSlim , car il est asynchrone/wait friendly (où il semble que ReaderWriterLockSlim ne l'est pas), ce qui peut aider avec un éventuel conflit de fil lorsque un nouveau HttpClient est requis. Là encore, le ReaderWriterLockSlim gérera mieux le problème potentiel de DateTime non atomique que vous avez signalé à juste titre, je vais donc devoir y réfléchir, merci !

L'approche basée sur une minuterie suggérée par @karelz ne nécessitera pas du tout de date/heure... la minuterie commuterait simplement le HttpClient. Vous auriez toujours besoin d'entourer le champ HttpClient d'une barrière mémoire (volatile, Interlocked.Exchange, etc.).

Ah j'avais mal lu ce qu'il voulait dire. Cela a du sens, même si je dois me familiariser avec les mécanismes de barrière mémoire pour le faire correctement.

Merci.

Edit : Juste pour ajouter, c'est une bonne raison pour laquelle je pense que quelque chose devrait être intégré pour gérer cela, afin que chaque consommateur de HttpClient n'ait pas à ré-implémenter/passer par cela.

Je me demande si c'est toujours un problème dans .net core 2.0 ? Avons-nous encore besoin de nous inquiéter du changement DNS ?

Je me demande si c'est toujours un problème dans .net core 2.0 ? Avons-nous encore besoin de nous inquiéter du changement DNS ?

Je crois comprendre que ce n'est pas un problème avec DNS lui-même, juste que HttpClient essaiera de réutiliser les connexions existantes (pour éviter l'épuisement des sockets), et donc même lorsque DNS change, vous vous connectez toujours à l'ancien serveur car vous passez par la connexion précédente.

@KallDrexx , cela signifie-t-il donc qu'il aura toujours des problèmes de déploiement bleu-vert ?

@withinoneyear de ma compréhension oui. Si vous créez un HttpClient et que vous l'utilisez contre Production Green, remplacez la production par Blue, le HttpClient aura toujours une connexion ouverte à Green jusqu'à ce que la connexion soit fermée.

Je sais que c'est ancien, mais je pense que vous ne devriez pas utiliser DateTime.UtcNow pour la mesure des intervalles de temps. Utilisez une source de temps monitonique comme Stopwatch.GetTimestamp. De cette façon, vous êtes à l'abri du réglage de l'heure locale par l'opérateur ou de la synchronisation de l'heure. Il y avait des chipsets buggés qui ont fait reculer les valeurs QPC, mais je ne pense pas que beaucoup d'entre eux soient utilisés maintenant.

var sp = ServicePointManager.FindServicePoint(new Uri("http://foo.bar/baz/123?a=ab"));
sp.ConnectionLeaseTimeout = 60*1000; // 1 minute

Ce code est placé dans le constructeur?

@whynotme8998 @lundcm Je ne pense pas. Si vous êtes HttpClient est singleton et que vous accédez à plusieurs points de terminaison, le constructeur ne serait pas le bon endroit pour le placer.
Vérifiez cette implémentation . Également dans le README du projet, il y a un lien vers un article de blog expliquant le problème. Cet article pointe également vers ce fil.

Quelqu'un peut-il m'aider à comprendre exactement ce que signifie ConnectionLeaseTimeout ?

Si, dans mon application, je le définis sur 1 minute, cela signifie-t-il que chaque minute, le bail de connexion expirera ? Qu'est-ce que cela signifie exactement pour parler avec mon back-end ?

Je vois que les gens parlent de la mise à jour DNS sur le back-end ? Sur une application Web Azure standard, la publication de mon back-end ASP.NET entraînerait-elle une actualisation DNS ?

Un délai d'attente de 1 minute ne laisserait-il pas potentiellement une fenêtre où le DNS a été mis à jour mais le délai d'attente n'a toujours pas eu lieu ?

Éditer. Se rendre compte que cela ne fonctionne pas dans .NET Standard 2.0. Quel est le travail autour?

En attendant cela https://www.stevejgordon.co.uk/introduction-to-httpclientfactory-aspnetcore ou en implémentant des morceaux vous-même.

La modification de ConnectionLeaseTimeout n'a pas fonctionné sur Xamarin avec .netstandard 2.0 !!!

@paradisehuman Je suppose que vous voulez dire ServicePoint.ConnectionLeaseTimeout . AFAIK, cela ne fonctionne pas non plus sur .NET Core. Dans .NET Core 2.1, nous avons introduit SocketsHttpHandler.PooledConnectionLifetime . De plus, le nouveau HttpClientFactory dans ASP.NET peut tirer parti des deux et fait encore plus pour vous.
Mono/Xamarin a sa propre implémentation de pile de mise en réseau (ils ne consomment pas de code source CoreFX pour la mise en réseau) - il serait donc préférable de signaler le bogue sur leur référentiel avec plus de détails.

Malheureusement, il n'y a aucun moyen de le faire avec .NET Core aujourd'hui. Soit ServicePointManager doit être transféré vers .NET Core, soit une fonctionnalité équivalente similaire doit être activée d'une autre manière.

@onovotny , SocketsHttpHandler dans .NET Core 2.1 expose PooledConnectionLifetime, qui sert un objectif similaire à ConnectionLeaseTimeout, juste au niveau du gestionnaire. Pouvons-nous considérer cette question abordée à ce stade?

@stephentoub vient de voir cela maintenant, oui, je pense que PooledConnectionLifetime devrait y remédier. La communauté peut ouvrir un autre problème si quelque chose est encore nécessaire.

@onovotny @karelz @stephentoub ,

Seriez-vous tous d'accord pour dire qu'il s'agit d'un résumé précis de la meilleure façon de résoudre le problème HttpClient/DNS singleton d'origine ?

  • Dans .NET Framework 2.0+, utilisez ServicePoint.ConnectionLeaseTimeout .

  • Dans .NET Core 2.1, utilisez SocketsHttpHandler.PooledConnectionLifetime .

  • Pour toutes les autres plates-formes/cibles/versions, il n'y a pas de solution/de piratage/de contournement fiable, alors ne vous embêtez même pas à essayer.

Alors que je continue d'apprendre des choses de ce fil et d'autres (comme ConnectionLeaseTimeout ne fonctionne pas de manière fiable sur toutes les plates-formes dans .NET Standard 2.0), je reviens à la planche à dessin en essayant de résoudre ce problème à partir d'une bibliothèque d'une manière qui fonctionne sur autant de plates-formes/versions que possible. Le reniflage de plate-forme est bien. Jeter/recréer périodiquement HttpClient est bien, si c'est efficace. Je suis assez certain que je me suis trompé lors de ma première tentative, qui consistait simplement à envoyer un en-tête connection:close à l'hôte à intervalles réguliers. Merci d'avance pour tout conseil!

@tmenier Pour toutes les autres plates-formes/cibles/versions, il n'y a pas de solution/hack/contournement fiable, alors ne vous embêtez même pas à essayer.

Vous pouvez toujours recycler l'instance régulièrement (par exemple, créez simplement une nouvelle instance et définissez-la sur une variable statique que d'autres utilisent).
C'est ce que fait HttpClientFactory . Vous pouvez choisir d'utiliser HttpClientFactory place.

@karelz Merci, je pense que cela me permet d'avancer. Peut-être devrais-je simplement ignorer le reniflage de la plate-forme et recycler les instances partout, ou est-il conseillé d'utiliser les autres approches lorsqu'elles sont disponibles (pour éviter les frais généraux, etc.) ?

Le plus délicat est peut-être de savoir _quand_ il est sûr de disposer des instances recyclées (je dois me soucier des demandes simultanées/en attente), mais je peux jeter un œil à la façon dont HttpClientFactory gère cela. Merci encore.

@tmenier Vous ne voulez pas les instances de recyclage tous les HttpClient appel, car cela vous mènera à l' épuisement tcp socket. Le recyclage doit être géré (timeout ou maintien d'un pool avec des HttpClient s qui peuvent être expirés.

@KallDrexx D'accord , je parle juste du recyclage _périodiquement_ d'un singleton (ou "pseudo"-singleton), par exemple toutes les quelques minutes. Je pense que cela impliquera la gestion d'un pool et une sorte d'élimination différée des instances mortes, une fois qu'il sera déterminé qu'elles n'ont aucune demande en attente.

Ah désolé j'ai mal compris ce que tu voulais dire par recycler.

Vous ne devriez pas avoir besoin de jeter les anciens. Laissez GC les récupérer.
Le code doit être aussi simple que de définir un nouveau "pseudo" singleton périodiquement en fonction de la minuterie. Rien de plus.

J'ai constaté que ne pas les éliminer peut entraîner des ralentissements lorsque vous manquez de connexions http dans des scénarios à hautes performances.

@tmenier À propos de l'utilisation de SocketsHttpHandler.PooledConnectionLifetime dans Dans .NET Core 2.1, la création de HttpClientHandler est complètement encapsulée dans https://github.com/dotnet/wcf/blob/master/src/System.Private.ServiceModel/src/System/ ServiceModel/Channels/HttpChannelFactory.cs. Existe-t-il un moyen de le faire lors de l'utilisation du client WCF ?

@edavedian Je suggérerais de demander sur le référentiel dotnet/wcf. cc @mconnew @Lxiamail

la pile sous-jacente se résout en WinHTTP ou en Curl qui n'exposent pas les boutons de contrôle avancés

Existe-t-il dans .Net Core un client HTTP qui fonctionne sur des sockets ?

Existe-t-il dans .Net Core un client HTTP qui fonctionne sur des sockets ?

Oui, SocketsHttpHandler, et depuis la 2.1 c'est la valeur par défaut.

Est-ce que HttpClient cache les URI qu'il atteint, de la même manière que RestClient, je crois ? Si tel est le cas, veuillez me faire savoir sur quelle version (.NET Core 3.0/.NET Framework 3.0, etc.) il prend en charge cela.

Je vois que la mise en cache n'est effectuée que dans RestClient si le projet est une application .Net Core 2.1+ ?

HttpClient cache-t-il les URI qu'il atteint, de la même manière que RestClient, je pense ?

HttpClient ne fait aucune mise en cache.

@SpiritBob , la forme de mise en cache à laquelle vous faites référence n'est pas claire. Ce problème est clos ; si vous voulez bien ouvrir un nouveau numéro avec des questions, nous pouvons vous aider à trouver des réponses.

@scalablecory Je crois que Davidsh a répondu avec ce que j'avais en tête. Merci!

Je viens de terminer la lecture de ce fil, et il semble qu'il y ait eu un cas d'utilisation qui n'a pas été abordé.

Lors de l'utilisation de HttpClientFactory , les HttpClient résultants fermeront-ils automatiquement les connexions et effectueront une nouvelle recherche DNS lorsqu'ils recevront un HttpRequestException avec un SocketException interne indiquant que le l'hôte n'est plus valide et que le DNS a potentiellement changé (code d'erreur 11001 - aucun hôte de ce type n'est connu) ?

Sinon, quelle est la solution pour que HttpClient effectue des recherches DNS avant que la durée de vie n'expire sur les enregistrements DNS ?

J'utilise actuellement HttpClientFactory avec un HttpMessageHandler (configuré via une injection de dépendance à l'aide de AddHttpClient<T, U>().ConfigurePrimaryHttpMessageHandler(...) ) et lorsqu'un enregistrement DNS change avant l'expiration de la durée de vie, une erreur se produit. Plus précisément, je constate que cela se produit lorsque vous effectuez un tas de téléchargements vers Azure Blob Storage.

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

EgorBo picture EgorBo  ·  3Commentaires

aggieben picture aggieben  ·  3Commentaires

yahorsi picture yahorsi  ·  3Commentaires

jamesqo picture jamesqo  ·  3Commentaires

matty-hall picture matty-hall  ·  3Commentaires