HttpClient - task was cancelled - How to get the exact error message?

40,852

Solution 1

The default HttpClient.Timeout value is 100 seconds (00:01:40). If you do a timestamp in your catch block you will notice that tasks begin to get canceled at exactly that time. Apparently there is a limited number of HTTP requests you can do per second, others get queued. Queued requests get canceled on timeout. Out of all 600k of tasks I personally got only 2500 successful, others got canceled.

I also find it unlikely, that you will be able to run the whole 600000 of tasks. Many network drivers let through high number of requests only for a small time, and reduce that number to a very low value after some time. My network card allowed me to send only 921 requests within 36 seconds and dropped that speed to only one request per second. At that speed it will take a week to complete all the tasks.

If you are able to bypass that limitation, make sure you build the code for 64-bit platform as the app is very hungry for memory.

Solution 2

Don't dispose the instance of HttpClient you're using. Weird but fixed for me this problem.

Solution 3

just wanted to share I have had a similar code to load test our servers ,and its a high probability that your requests are timing out. You can set the timeout for your http request to max and see if it changes anything for you. I tried hitting our servers by creating various threads. And it increased the hits but they would all eventually timeout.And also you cannot set a timeout when hitting them on another thread.

Share:
40,852
Michael Sync
Author by

Michael Sync

#SOreadytohelp

Updated on April 26, 2020

Comments

  • Michael Sync
    Michael Sync about 4 years

    I have the following test code. I always get the "Task was cancelled" error after looping 316934 or 361992 times.

    If I am not wrong, there are two possible reasons why the task was cancelled a) HttpClient got timeout or b) too many tasks in queue and some tasks got time-out.

    I couldn't find the documentation about the limitation in queueing the tasks. And I tried creating more than 500K tasks and no time-out. I guess the reason "b" might not be right.

    Q1. Is there any other reason that I missed out?

    Q2. If it's because HttpClient timeout, how can I get the exact exception message instead of "TaskCancellation" exception.

    Q3. What would be the best way to fix it? Should I introduce the throttler?

    Thanks!

    var _httpClient = new HttpClient();
    _httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Accept", "text/html,application/xhtml+xml,application/xml");
    _httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Accept-Encoding", "gzip, deflate");
    _httpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:19.0) Gecko/20100101 Firefox/19.0");
    _httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Accept-Charset", "ISO-8859-1");
    
    int[] intArray = Enumerable.Range(0, 600000).ToArray();
    
    var results = intArray                
        .Select(async t => {
    
            using (HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, "http://www.google.com")) {
                log.Info(t);
    
                try {
    
                    var response = await _httpClient.SendAsync(requestMessage);
                    var responseContent = await response.Content.ReadAsStringAsync();
    
                    return responseContent;
                }
                catch (Exception ex) {
                    log.ErrorException(string.Format("SoeHtike {0}", Task.CurrentId), ex);
                }
                return null;
            }
        });
    
    Task.WaitAll(results.ToArray());
    
    Console.ReadLine();
    

    Here is the step to replicate the issue.

    1. Create a Console Project in VS 2012.

    2. Please copy and paste my code in Main.

    3. Put the breakpoint at this line " log.ErrorException(string.Format("SoeHtike {0}", Task.CurrentId), ex);"

    Run the program in debug mode. Wait for a few minutes. (maybe 5 minutes? ) I just tested my code and I got the exception after 3 mins. If you have fiddler, you can monitor the requests so that you know the program is still running or not.

    Feel free to let me know if you can't replicate the issue.

  • jpgrassi
    jpgrassi over 8 years
    I was creating just a console app to send a lot of requests to an API to simulate a "real" world case and this was the only thing that worked for me. Very weird for sure.
  • user123456
    user123456 over 8 years
    hi, can you please elaborate more in your answers. I am getting the same issue. How can I find out how many tasks running in my app ?
  • Veverke
    Veverke about 8 years
    wow, I have been going nuts with this and... yours was the only thing that fixed it. Was doing more or less the same as @jpgrassi.
  • frostymarvelous
    frostymarvelous over 7 years
    Timeout. Thanks, that's what I was looking for.
  • Sergey.quixoticaxis.Ivanov
    Sergey.quixoticaxis.Ivanov over 7 years
    It's not weird, MSDN explains why and how you should use HttpClient. If you're interested, you may also inspect CIL of the class to see why it should not be disposed frequently for yourself.
  • abatishchev
    abatishchev over 7 years
    @Sergey.quixoticaxis.Ivanov: this article's code samples says (sic): "// Need to call dispose on the HttpClient object when done using it, so the app doesn't leak resources". Also a generally and widely accepted pattern is to dispose everything what implements IDisposable.
  • Sergey.quixoticaxis.Ivanov
    Sergey.quixoticaxis.Ivanov over 7 years
    @abatishchev HttpClient is intended to be instantiated once and re-used throughout the life of an application. Instantiating an HttpClient class for every request will exhaust the number of sockets available under heavy loads. This will result in SocketException errors Your choice, but following this widely accepted pattern often makes code slow, ugly and even unreliable (in general and when meeting classes like HttpClient that are 100% not meant to be used that way).
  • Sergey.quixoticaxis.Ivanov
    Sergey.quixoticaxis.Ivanov over 7 years
    @abatishchev I don't say it should not be disposed at all (while it's also possible), but the article I've linked mentions clearly that you shouldn't be doing so frequently.
  • Jenk
    Jenk over 7 years
    @abatishchev the point here is "when done using it" doesn't mean "when done making a request", but "when you are done making all of your requests."
  • mortb
    mortb about 7 years
    Well, this is confusing. If I were to create a desktop application I think that I could instantiate the HttpClient once, but I am working on a web app. What would be the best way to instantiate the HttpClient then? If I just have one global client for that is used by the code that handles every incomming request, how would that scale?
  • abatishchev
    abatishchev about 7 years
    @mortb: the best practice would to reuse singleton instance of HttpClient. However it's not that good option if you need to customize HTTP headers. Then you either reuse an instance within that scope, or can't use the {Method}Async family of methods (e.g. GetAsync()) and end up using PostAsync directly, the only method accepting HttpRequestMessage where you can perform the customization. If it's not your case, then just reuse singleton instance of HttpClient