Is HttpClient safe to use concurrently?
Asked Answered
J

3

204

In all the examples I can find of usages of HttpClient, it is used for one off calls. But what if I have a persistent client situation, where several requests can be made concurrently? Basically, is it safe to call client.PostAsync on 2 threads at once against the same instance of HttpClient.

I am not really looking for experimental results here. As a working example could simply be a fluke (and a persistent one at that), and a failing example can be a misconfiguration issue. Ideally I'm looking for some authoritative answer to the question of concurrency handling in HttpClient.

Jehius answered 24/6, 2012 at 14:22 Comment(1)
Also read this question for more info on how to properly use HttpClient and dispose of it: #15705592Infertile
T
208

According to Microsoft Docs, since .NET 4.5 The following instance methods are thread safe (thanks @ischell):

CancelPendingRequests
DeleteAsync
GetAsync
GetByteArrayAsync
GetStreamAsync
GetStringAsync
PostAsync
PutAsync
SendAsync
PatchAsync
Tirol answered 24/6, 2012 at 14:25 Comment(14)
Yeah, I wasn't sure about that one, as it appears to be a standard warning on everything on MSDN (and I remember reading some MSDN blogs about how sometime that warning is wrong, as it is applied blindly to everything).Jehius
@AlexK: Well, I wouldn't believe anything I hear. Take a look at this one: msdn.microsoft.com/en-us/library/dd287191.aspx. So, I would generally trust MSDN.Tirol
Well, the blogs are also on MSDN, a conundrum :) At any rate, I guess I'll err on the side of caution, and do client per request strategy.Jehius
On the other hand, HttpClient has a CancelPendingRequests which "Cancel[s] all pending requests on this instance." - that seems to suggest that it can have multiple requests in flight.Fortitude
This is wrong; in the remarks section of the MSDN page you linked, it says that GetAsync, PostAsync, etc. are all thread safe.Lecithinase
@ischell: I can assure you that the paragraph in question was not there at the time this issue was discussed.Tirol
FYI it still says instance methods are not thread-safe at the bottom of the MSDN page.Childish
@Matt: That's always been there and is a general note about thread safety for all .NET types. See the Remarks section up above in the MSDN article.Tirol
So Microsoft have designed HttpClient to be reusable but then the class has instance data for headers: client.DefaultRequestHeaders.Accept.Add(...);Unchaste
I'm not sure if HttpClient is thread-safe. There are 2 scenarios here: 1. Calling client.GetAsync(), waiting for it to return a Task object, then calling it again (on any thread) - should be OK - there is no concurrency with our calls. The HttpClient handles the request in the background and completes each task once the request is done, or 2. Calling client.GetAsync() repeatedly on multiple threads without waiting for the Task object to be returned each time. This is concurrency and I doubt this is supported out of the box. Async methods are not guaranteed to provide thread safety (case #2).Photocathode
In late, but I wanted to comment on @cwills. DefaultRequestHeaders are just that, defaults. If you want different headers on a per-request-basis, you can create new StringContent(), set additional headers on that, then use the overload that takes URI and HttpContent.Phantom
HttpClient also has a default maximum connections per server (HttpClientHandler.MaxConnectionsPerServer) of just 2. Make sure you increase that, or your multi-threaded requests will just block.Fluorine
Also, to set different Uri's and headers on the threaded requests, you can use an HttpRequestMessage and pass that to SendAsync for example.Fluorine
Does anyone know if this singleton pattern for HttpClient is safe to use server-side on an application that will have multiple users?Copenhagen
C
107

Here is another article from Henrik F. Nielsen about HttpClient where he says:

"The default HttpClient is the simplest way in which you can start sending requests. A single HttpClient can be used to send as many HTTP requests as you want concurrently so in many scenarios you can just create one HttpClient and then use that for all your requests."

Camellia answered 15/11, 2012 at 23:44 Comment(10)
What about if the username and password can change in between threads? that's what i can't seem to find anyone talking aboutSublimity
@NicholasDiPiazza: how often does it change? If there's a known set of user/password pairs then you can create a pool of HttpClient instances.Tirol
yep that's what I ended up doingSublimity
Note that reusing the same HttpClient for all your requests might result in stale DNS issues: github.com/dotnet/corefx/issues/11224.Pindus
@OhadSchneider If believe that issue is limited to .net core. You can fix the issue with .net 4 by injecting a custom HttpClientHandler into the HttpClient constructor then setting the "ConnectionLeaseTimeout". However, if no requests are sent to the endpoint for 100 seconds the connection will refresh on its own. protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,CancellationToken cancellationToken) { var sp = ServicePointManager.FindServicePoint(request.RequestUri); sp.ConnectionLeaseTimeout = 100 * 1000; }Known
What's the point? Is an HttpClient particularly expensive to where you shouldn't create a new one for each request?Ferocious
@Ferocious simple answer: yes, disposing it will quickly exhaust your TCP sockets under load. Long answer: it's complex, and no one really knows the right way to use it. aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong https://mcmap.net/q/76441/-do-httpclient-and-httpclienthandler-have-to-be-disposed-between-requests nimaara.com/beware-of-the-net-httpclient learn.microsoft.com/en-us/azure/architecture/antipatterns/…Successful
Also https://mcmap.net/q/76792/-what-is-the-overhead-of-creating-a-new-httpclient-per-call-in-a-webapi-client and https://mcmap.net/q/77171/-httpclientfactory-create-vs-new-httpclientSuccessful
@NicholasDiPiazza User name and password belong to the request header, not the underlying HTTP client. From my experience, creating HTTP client instances will quickly exhaust your server TCP connections pool. I learned this the hard way watching our servers on Azure burn down with no explanation because of this (we only realized the issue after looking at the server connections pool)Nutritious
@Nutritious right. in many situations with low load, you can just kind of ignore this. but when you have a high load batch or web process that is used 1000's of times over an hour, then you need to be smart about when to open a connection, and when to wait until the pool has one free.Sublimity
J
23

Found one MSDN forum post by Henrik F. Nielsen (one of HttpClient's principal Architects).

Quick summary:

  • If you have requests that are related (or won't step on eachother) then using the same HttpClient makes a lot of sense.

  • In genral I would recommend reusing HttpClient instances as much as possible.

Jehius answered 25/6, 2012 at 14:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.