Async webrequest times out => сбой IIS

у меня есть веб-приложение, которое получает данные из внешних сервисов. Сам запрос происходит, как код ниже - довольно просто, насколько я могу видеть. Создайте запрос, запустите его асинхронно и позвольте обратному вызову обработать ответ. Отлично работает в моей среде разработки.

public static void MakeRequest(Uri uri, Action<Stream> responseCallback)
        {
            WebRequest request = WebRequest.Create(uri);
            request.Proxy = null;
            request.Timeout = 8000;
            try
            {
                Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null)
                    .ContinueWith(task =>
                                      {
                                          WebResponse response = task.Result;
                                          Stream responseStream = response.GetResponseStream();
                                          responseCallback(response.GetResponseStream());
                                          responseStream.Close();
                                          response.Close();
                                      });
            } catch (Exception ex)
            {
                _log.Error("MakeRequest to " + uri + " went wrong.", ex);
            }
        }

однако внешние тестовые среды и производственная среда могут по причинам, не зависящим от меня, не достичь целевого URL-адреса. Хорошо, подумал я - тайм-аут запроса никому не повредит. Однако, казалось, что каждый раз, когда этот запрос истекал, ASP.NET сбой и IIS был перезапущен. Журнал событий показывает мне, среди прочего, этот stacktrace:

StackTrace:    at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   at System.Threading.Tasks.Task`1.get_Result()
   at MyApp.AsyncWebClient.<>c__DisplayClass2.<MakeRequest>b__0(Task`1 task)
   at System.Threading.Tasks.Task`1.<>c__DisplayClass17.<ContinueWith>b__16(Object obj)
   at System.Threading.Tasks.Task.InnerInvoke()
   at System.Threading.Tasks.Task.Execute()

InnerException: System.Net.WebException

Message: Unable to connect to the remote server

StackTrace:    at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endMethod, TaskCompletionSource`1 tcs)

InnerException: System.Net.Sockets.SocketException

Message: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond

StackTrace:    at System.Net.Sockets.Socket.EndConnect(IAsyncResult asyncResult)
   at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure, Socket s4, Socket s6, Socket& socket, IPAddress& address, ConnectSocketState state, IAsyncResult asyncResult, Int32 timeout, Exception& exception)

..так что все это сводится к SocketException, мне кажется. И сразу после этого (в течение той же секунды) регистрируется другое событие (которое, как я предполагаю, актуально):

Exception Info: System.AggregateException
Stack:
   at System.Threading.Tasks.TaskExceptionHolder.Finalize()

это своего рода за пределами меня, поскольку я не мастер асинхронного кода и потоковой передачи, но что тайм-аут от веб-запросов вызывает IIS для сбоя кажется очень странным. Я переосмыслил MakeRequest выполнять запросы синхронно, что отлично работает. Запрос все еще раз в этих средах, но никакого ущерба не наносится, и приложение продолжает работать счастливо навсегда.

Итак, я решил свою проблему, но почему это происходит? Может кто-нибудь просветить меня? :-)

1 ответов


ваше продолжение должно справиться с тем, что .Result может отражать исключение. В противном случае у вас есть необработанное исключение. Необработанные исключения убивают процессы.

.ContinueWith(task =>
{
    try {
        WebResponse response = task.Result;
        Stream responseStream = response.GetResponseStream();
        responseCallback(responseStream);
        responseStream.Close();
        response.Close();
    } catch(Exception ex) {
        // TODO: log ex, etc
    }
});

код старый обработчик исключений охватывает только создание задачи - не отзвонились.