3

Current Situation

There is a client that does a get-request by HttpClient.GetAsync. Unfortunately, for some reason, we need to block on that calls.

In order to do so, this Asynchelper class is used in order to avoid context-switch deadlocks (instead of just using .Result)

   public static class AsyncHelper
   {
       private static readonly TaskFactory _myTaskFactory = new
             TaskFactory(CancellationToken.None,
                         TaskCreationOptions.None,
                         TaskContinuationOptions.None,
                         TaskScheduler.Default);


    public static void RunSync(Func<Task> func)
    {
        AsyncHelper._myTaskFactory
          .StartNew<Task>(func)
          .Unwrap()
          .GetAwaiter()
          .GetResult();
    }
}

Then the actual call looks like this:

AsyncHelper.RunSync(Async Function() Await _httpClient.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead))

Problem

During a stress test using Netlimiter to reduce the network speed, we encountered a problem with requests that did not finish. For example, when I kill a network connection (in NetLimiter), such a request will stay forever on client side. It will stay in the AsyncHelper.RunSync-call until it runs into the httpClient.Timeout.

Shouldn't there be an exception that will end this call when the connection is lost? Am I missing something?

DanielG
  • 1,217
  • 1
  • 16
  • 37
  • So is that "Forever" or "until...timeout"? – Yam Marcovic Jan 28 '16 at 16:35
  • If you are blocking your main thread with a `.GetResult()` call anyway, instead of using `HttpClient` and this helper class use `WebClient` instead. It has synchronous versions of methods you can call and you can get rid of all this crazy TaskFactory wrapper layer. – Scott Chamberlain Jan 28 '16 at 16:43
  • You shouldn't be using `StartNew` http://blog.stephencleary.com/2013/08/startnew-is-dangerous.html – Chris Marisic Jan 28 '16 at 16:48
  • @ChrisMarisic The usage here seems fine. – i3arnon Jan 28 '16 at 17:04
  • This code is also all pointless. All OP needs is `httpClient.GetAsync(...).GetAwaiter().GetResult()` but this isn't even the real issue. The real issue is OP's misunderstanding of HTTP/TCP like Yam answered. – Chris Marisic Jan 28 '16 at 18:01

1 Answers1

3

The thing is that HTTP connections are usually riding over a TCP connection. So when you forcefully terminate a TCP connection without its being able to send its "I'm done here," (or FIN) packets, the other end of the connection is still happy to wait for more data, at least until some defined timeout which can be configured from above in socket-query operations.

One way to handle this is to set TCP Keep-Alive on the sockets. Note that this is very different from HTTP Keep-Alive. The other option is, as already seems to happen, to use a good-enough timeout.

Yam Marcovic
  • 7,953
  • 1
  • 28
  • 38
  • ok, thanks :). That really helps understanding the issue. I think we will go with a good-enough timeout setting, since this seems to be a rare case anyway. – DanielG Jan 28 '16 at 18:19