28 votes

Réglage HttpClient pour un trop court délai accidents de processus

J'ai remarqué que lorsque je suis à l'aide d' System.Net.HttpClient avec un court délai, il peut parfois se bloquer le processus, même quand il est enveloppé dans un bloc try-catch. Voici un court programme de reproduire cela.

public static void Main(string[] args)
{
    var tasks = new List<Task>();
    for (int i = 0; i < 1000; i++)
    {
        tasks.Add(MakeHttpClientRequest());
    }
    Task.WaitAll(tasks.ToArray());

}

private async static Task MakeHttpClientRequest()
{            
    var httpClient = new HttpClient { Timeout = TimeSpan.FromMilliseconds(1) };
    var request = "whatever";
    try
    {
        HttpResponseMessage result =
            await httpClient.PostAsync("http://www.flickr.com/services/rest/?method=flickr.test.echo&format=json&api_key=766c0ac7802d55314fa980727f747710",
                                 new StringContent(request));             
        await result.Content.ReadAsStringAsync();                
    }
    catch (Exception x)
    {
        Console.WriteLine("Error occurred but it is swallowed: " + x);
    }
}

L'exécution de cette plante le processus avec l'exception suivante:

Unhandled Exception: System.AggregateException: One or more errors occurred. ---> System.Net.WebException: The request was canceled
   at System.Net.ServicePointManager.FindServicePoint(Uri address, IWebProxy proxy, ProxyChain& chain, HttpAbortDelegate& abortDelegate, Int32& abortState)
   at System.Net.HttpWebRequest.FindServicePoint(Boolean forceFind)
   at System.Net.HttpWebRequest.get_ServicePoint()
   at System.Net.AuthenticationState.PrepareState(HttpWebRequest httpWebRequest)
   at System.Net.AuthenticationState.ClearSession(HttpWebRequest httpWebRequest)
   at System.Net.HttpWebRequest.ClearAuthenticatedConnectionResources()
   at System.Net.HttpWebRequest.Abort(Exception exception, Int32 abortState)
   at System.Net.HttpWebRequest.Abort()
   at System.Net.Http.HttpClientHandler.OnCancel(Object state)
   at System.Threading.CancellationCallbackInfo.ExecutionContextCallback(Object obj)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.CancellationCallbackInfo.ExecuteCallback()
   at System.Threading.CancellationTokenSource.CancellationCallbackCoreWork(CancellationCallbackCoreWorkArguments args)
   at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
   --- End of inner exception stack trace ---
   at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)
   at System.Threading.CancellationTokenSource.NotifyCancellation(Boolean throwOnFirstException)
   at System.Threading.CancellationTokenSource.TimerCallbackLogic(Object obj)
   at System.Threading.TimerQueueTimer.CallCallbackInContext(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.TimerQueueTimer.CallCallback()
   at System.Threading.TimerQueueTimer.Fire()
   at System.Threading.TimerQueue.FireNextTimers()
   at System.Threading.TimerQueue.AppDomainTimerCallback()

En creusant un peu, il semble que lorsque l' HttpClient abandonne la demande avant pertinente ServicePoint est créé, HttpWebRequest tente de créer l' ServicePoint, via ServicePointManager.FindServicePoint, ce qui jette un RequestCanceled. Depuis cette exception est levée dans le thread qui tente d'annuler la demande, il n'est pas pris, et le processus meurt.

Ai-je raté quelque chose? Avez-vous rencontré ce problème?

15voto

Tratcher Points 176

HttpWebRequest.Abort() est de lancer une exception sur un arrière-plan/thread horloge. Cela n'a rien à voir avec HttpClient de gestion des Tâches.

L'exception d' HttpWebRequest.Abort() doit être fixé dans la .NET 4.5 GDR1. http://support.microsoft.com/kb/2750149 http://support.microsoft.com/kb/2750147

4voto

Roy Ashbrook Points 383

On dirait qu'il est une sorte de bug dans la façon dont l'async gestionnaire pour HttpClient, c'est de gérer les tâches. J'ai été en mesure de lancer les éléments en parallèle, mais de les exécuter de façon synchrone, et cela fonctionne. Je ne suis pas sûr si vous voulez juste éviter l'erreur non gérée ou non. Cette couru tâches parallèles, mais ils ne sont pas async vraiment depuis que je l'ai éteint. Sur mon ordinateur, je serait toujours obtenir les 5 tours et il se plantait. Même si je l'ai mis en attente après une seconde, c'est comme les accidents dans les fils serait encore exploser si elles étaient asynchrone.

Je pense que c'est un bug, je ne peux pas imaginer que c'est un comportement intentionnel.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;

namespace TestCrash
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Parallel.ForEach(Enumerable.Range(1, 1000).ToList(), i =>
                {
                    Console.WriteLine(i);
                    using (var c = new HttpClient { Timeout = TimeSpan.FromMilliseconds(1) })
                    {
                        var t = c.GetAsync("http://microsoft.com");
                        t.RunSynchronously(); //<--comment this line and it crashes
                        Console.WriteLine(t.Result);
                    }
                });
            }
            catch (Exception x)
            {
                Console.WriteLine(x.Message);
            }
            Console.ReadKey();
        }
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X