valor - tiempo de espera de la operación de espera agotado c#
Configuración de HttpClient en un proceso de bloqueo de tiempo de espera demasiado corto (2)
Me di cuenta de que cuando uso System.Net.HttpClient
con un corto tiempo de espera, a veces puede interrumpir el proceso, incluso cuando está envuelto en un bloque try-catch. Aquí hay un programa corto para reproducir esto.
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);
}
}
Ejecutar esto bloqueará el proceso con la siguiente excepción:
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()
Profundizando un poco, parece que cuando HttpClient
cancela la solicitud antes de que se cree un ServicePoint
relevante, HttpWebRequest
intenta crear el ServicePoint
, a través de ServicePointManager.FindServicePoint
, que arroja un RequestCanceled. Como esta excepción se lanza en el hilo que intenta cancelar la solicitud, no se captura, y el proceso muere.
¿Me estoy perdiendo de algo? ¿Te has encontrado con este problema?
Parece que hay algún tipo de error en la forma en que el controlador asincrónico de HttpClient está administrando las tareas. Pude lanzar los elementos en paralelo, pero los ejecuté sincrónicamente y funciona. No estoy seguro de si desea evitar el error no controlado o no. Esto ejecutó tareas paralelas, pero no son asincrónicas realmente desde que lo apagué. En mi computadora, siempre llegaba a 5 rondas y se bloqueaba. Incluso si configuro el tiempo de espera después de un segundo, es como si los bloqueos en los hilos aún explotaran si fueran asincrónicos.
Creo que es un error, no me puedo imaginar que este sea el comportamiento previsto.
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();
}
}
}
HttpWebRequest.Abort()
está lanzando una excepción en un hilo de fondo / temporizador. Esto no tiene nada que ver con la gestión de tareas de HttpClient.
La excepción de HttpWebRequest.Abort()
debe corregirse en .NET 4.5 GDR1. http://support.microsoft.com/kb/2750149 http://support.microsoft.com/kb/2750147