18

When instancing an HttpClient, the one common piece of advice is:

However, based on this link I see commentary which I think implies another rule:

The HttpClient class instance acts as a session to send HTTP requests. An HttpClient instance is a collection of settings applied to all requests executed by that instance. In addition, every HttpClient instance uses its own connection pool, isolating its requests from requests executed by other HttpClient instances.

This makes me wonder if I am supposed to create one HttpClient instance for each service-endpoint I interact with. By "service-endpoint", I mean a distinct base address. Each of the following would be a distinct "service-endpoint":

Certainly if I intend on using the "BaseAddress" property of the HttpClient, and if I'm dealing with concurrent calls, then I will need to have one instance of HttpClient per "service-endpoint".

However, HttpClient does allow me to specify an absolute address explicitly:

HttpClient client = new HttpClient(...);

client.PostAsJsonAsync("http://foo.net/api/Message/", ...);
client.PostAsJsonAsync("http://bar.com/api/Message/", ...);
client.PostAsJsonAsync("http://wow.gov/api/Message/", ...);
client.PostAsJsonAsync("http://now.com/api/Message/", ...);
client.PostAsJsonAsync("http://mom.org/api/Message/", ...);
client.PostAsJsonAsync("http://dog.com/api/Message/", ...);

The above code works, and it is exactly what I want for the current application I'm building. But the nagging question remains...am I doing something wrong if I use one HttpClient for all service-endpoints my application communicates with?

Is there a reason why I would truly need the "connection pool isolation" that was mentioned in the above quotation?

Community
  • 1
  • 1
Brent Arias
  • 29,277
  • 40
  • 133
  • 234
  • *because I'm making many endpoints share the same connection pool.* Could you please expand on that? What do you mean by endpoints? How will you be using `HttpClient`? To call externel HTTP endpoints? – Yuval Itzchakov Apr 30 '15 at 20:13
  • From personal experience, I think the answer mostly depends on what kind of concurrency and throughput you need. I've found that a single instance of an HttpClient bogs down after a while and multiple instances _can_ help. Having said that, with sufficient volume, you will exhaust the resources of the server and may need to scale horizontally. – David Peden Apr 30 '15 at 20:18
  • I've revised my question to clarify "service endpoint", and the problem I'm concerned with. Yes, I will use HttpClient to call external HTTP endpoints. – Brent Arias Apr 30 '15 at 20:35

2 Answers2

2

But I want to know if I will be compromising the inner workings of HttpClient because I'm making many endpoints share the same connection pool.

No, I don't think a single instance of HttpClient will exhaust your resources, but that really depends on how many concurrent requests you'll be making. HttpClient is designed to serve concurrent requests, and by using asynchronous API's such (XXXAsync), you can achieve just that.

I would advise not to forget to set ServicePointManager.DefaultConnectionLimit to a higher number, as it's default value is 2 (concurrent requests).

Also, If you think you'll be hitting the wall quickly with a single instance, I'd suggest as always to profile your application to understand the exact bottleneck.

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • This - "I would advise not to forget to set ServicePointManager.DefaultConnectionLimit to a higher number, as it's default value is 2 (concurrent requests)." - is incorrect. The default value is 2 ... but it means no restrictions (saner APIs use the values -1 or 0 in a similar way). Unless you set the DefaultConnectionLimit yourself HttpClient will create thousands of concurrent connections without regret. – Test_me Feb 23 '17 at 10:38
  • @Test_me Who gives that guarantee? That's definitely not [what the docs say](https://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.defaultconnectionlimit(v=vs.110).aspx): *The maximum number of concurrent connections allowed by a ServicePoint object.* Also, read [this](https://blogs.msdn.microsoft.com/jpsanders/2009/05/20/understanding-maxservicepointidletime-and-defaultconnectionlimit/). – Yuval Itzchakov Feb 23 '17 at 11:28
  • The docs are incorrect: "The strange thing is that according to MSDN, the default value for the connection limit is 2. I also checked that on my side using the debugger which pointed that indeed 2 is the default value. However, it seems that unless explicitly setting a value to ServicePointManager.DefaultConnectionLimit, the default value will be ignored. Since I didn't explicitly set a value for it during my HttpClient tests I thought it was ignored." http://stackoverflow.com/questions/16194054/is-async-httpclient-from-net-4-5-a-bad-choice-for-intensive-load-applications – Test_me Feb 23 '17 at 12:31
  • @Test_me I would definitely not rely on a single testament from a single person on StackOverflow. Where did he run the tests? Was it on his local PC or was it on a server? That makes a difference. Other than that, you're referring to an implementation detail. If the docs say it is to be respected and it currently isn't, that is a bug. What happens if this changes in the next .NET version or .NET core? You can definitely not put your money on *not setting* that value explicitly – Yuval Itzchakov Feb 23 '17 at 12:36
  • It's not a single person comment - that's just how the API works. Microsoft is not going to change the behavior and break countless systems. – Test_me Feb 24 '17 at 15:44
  • @Test_me That is not how the API is documented, therefor it doesn't constraint Microsoft to obey it. The way it works is an implementation detail, which again, I am definitely against. How much does it cost you to explicitly assign a value to `ServicePoint`? Near nothing, than why not do it? – Yuval Itzchakov Feb 24 '17 at 15:52
  • 4
    why oh why is there so much conflicting and crap data out there surrounding httpclient? it's insane. – Brady Moritz Jun 01 '18 at 03:43
1

I faced with the same question too.

And there are results of my investigation:

  1. Use separate instances of HttpClient just if you need to change its non thread-safely settings (DefaultRequestHeaders, BaseAddress) during requests. It would be useful and safely to create separate instances with set of those specific settings for each instance. Some more details: HttpClient–Is It Really Thread-Safe?

  2. Ok, I create specific instance of HttpClient, but I wan't to use BaseAdress. From point 1) I need to use new HttpClient instance per unique BaseAdress (host).

    But what if I use HttpClient for requests to multiple hosts without BaseAdress by absolute address? You can chase the calls from HttpClient to SocketsHttpHanlder to HttpConnectionPoolManager (dotnet source code) and see it creates separate 'HttpConnectionPool' for each host and add the pool to 'ConcurrentDictionary' _pools. That means we have separate pool for each unique host anyway. That's why I prefer to use single HttpClient instance for multiple hosts without BaseAdress usage.

Klyuch
  • 66
  • 1
  • 6