HttpClient - task was cancelled - How to get the exact error message?
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.
Comments
-
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.
Create a Console Project in VS 2012.
Please copy and paste my code in Main.
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 over 8 yearsI 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 over 8 yearshi, 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 about 8 yearswow, 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 over 7 yearsTimeout. Thanks, that's what I was looking for.
-
Sergey.quixoticaxis.Ivanov over 7 yearsIt'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 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 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 likeHttpClient
that are 100% not meant to be used that way). -
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 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 about 7 yearsWell, 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 theHttpClient
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 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 usingPostAsync
directly, the only method acceptingHttpRequestMessage
where you can perform the customization. If it's not your case, then just reuse singleton instance of HttpClient