Recently, we migrated our applications to latest windows server from 2008 and ran into a number of issues with sockets, connection limits and timeouts. The root of our issues is the default connection limits that we had not encountered before. Below is part of our investigation and subsequent resolution to these issues.
- October 9, 2019
On .Net Full framework, you can control the number of outgoing client connections by setting ServicePointManager.DefaultConnectionLimit to the desired number. It is 2 by default.
On .Net Core, you can set it by changing HttpClientHandler.MaxConnectionsPerServer to your desired limit. The default is int.MaxValue -- much higher than the default for the full framework. Gets or sets the maximum number of concurrent connections (per server endpoint) allowed when making requests using an HttpClient object. Note that the limit is per server endpoint, so for example a value of 256 would permit 256 concurrent connections to http://www.adatum.com/ and another 256 to http://www.adventure-works.com/
Before the introduction of the HttpClientFactory in .NET Core 2.1, it was common to use the HttpClient to make HTTP requests to services. One of the big problems with using the HttpClient was the misuse of it. HttpClient implements IDisposable, when anything implements IDisposable, best practice tells us that we should wrap the calls we are making inside a using statement to allow proper disposal of the object. However the HTTPClient is different, even though it implements IDisposable, we shouldn’t be wrapping this in a using statement. The HttpClient is reusable and thread safe, so it makes it very inefficient and unnecessary to dispose of the HttpClient after each request is made. When you dispose of the HttpClient object the underlying socket is not immediately released. This can cause some serious issues like ‘sockets exhaustion’. The recommended way is to instantiated it once and reused it throughout the life of an application.
YOU'RE USING HTTPCLIENT WRONG AND IT IS DESTABILIZING YOUR SOFTWARE
Unfortunately, not disposing of our HttpClient instance does not fix all of the issues with the HttpClient. The issue with creating a single instance of the HttpClient is that it won’t respect DNS changes, because we are creating a single instance of the HttpClient, we are keeping the connection open, ready to be reused.
Due to these issues, the HttpClientFactory was created.
Using the HttpClientFactory removes the issues that we can run into when using the HttpClient, such as ‘sockets exhaustion’, due to not re-using the HttpClient throughout the life of an application.
When reusing your HttpClient you could then run into the issue of the client not respecting DNS changes. While the HttpClientFactory by default has a handler lifetime set to 2 mins, to get around DNS change issue, we are also able to set this handler lifetime to whatever we want.