CurrentConnections exceeds ConnectionLimit in ServicePoint

1.5k views Asked by At

I have a cluster/server with multiple nodes that handle requests from the application.

The application the user is running, opens 2 web clients with the following URLs:

In order to support stickiness (I want each of the 2 web clients will keep the connection against the nodes - persistence), the ConnectionLeaseTimeout stayed with the default value, which means "don't close the connection" and because the DefaultPersistentConnectionLimit is 2 by default, I set the DefaultConnectionLimit to 1.

The problem:

  1. servicePoint.CurrentConnections is 2, although servicePoint.ConnectionLimit is 1.

  2. In the server, I see that the remote host port is changing, i.e. I see more than 2 ports (more than 1 port for each client).

What am I doing wrong?

My class output:

CommunicationWebClient https://myprocess.myapp.com/api/json/v1

CommunicationWebClient https://myprocess.myapp.com/api/protobuf/v1

SendAsync _uri=https://myprocess.myapp.com/api/json/v1 servicePoint.Address=https://myprocess.myapp.com/api/json/v1 servicePoint.ConnectionLimit=1 servicePoint.CurrentConnections=2

...

SendAsync _uri=https://myprocess.myapp.com/api/protobuf/v1 servicePoint.Address=https://myprocess.myapp.com/api/json/v1 servicePoint.ConnectionLimit=1 servicePoint.CurrentConnections=2

...

public sealed class CommunicationWebClient : IDisposable
{
    private HttpClient _httpClient;
    private Uri _uri;

    public CommunicationWebClient(Uri uri)
    {
        Logger.Debug($"{nameof(CommunicationWebClient)} {nameof(uri)}={uri}");

        _uri = uri;

        ServicePointManager.DefaultConnectionLimit = 1;

        _httpClient = new HttpClient(new WebRequestHandler())
        {
            Timeout = 10.Minutes(),
        };
    }

    public void Dispose()
    {
        _httpClient.Dispose();
    }


    public async Task SendAsync(
        ByteArrayContent content)
    {
        var servicePoint = ServicePointManager.FindServicePoint(_uri);

        Logger.Debug($"{nameof(SendAsync)} " +
                    $"{nameof(_uri)}={_uri} " +
                    $"{nameof(servicePoint.Address)}={servicePoint.Address} " +
                    $"{nameof(servicePoint.ConnectionLimit)}={servicePoint.ConnectionLimit} " +
                    $"{nameof(servicePoint.CurrentConnections)}={servicePoint.CurrentConnections}");

        using (var httpResponseMessage = await _httpClient.PostAsync(_uri, content))
        {
            ...
        }
    }
}
2

There are 2 answers

0
Fox Desert On

In most cases, http client are recommended to use one per application. Disposing http client doesn't get throwing the socket it used right away .

0
Anton Kukharenko On

If you still have a problem, check that your CommunicationWebClient is not disposed too often. It disposes HttpClient but it behaves not as usually people expect.

Checkout this article: https://learn.microsoft.com/en-us/azure/architecture/antipatterns/improper-instantiation/

Shortly speaking when you dispose HttpClient in case of windows, you ask windows to close all opened sockets. But by default windows have 4 minute timeout to completely close the socket. So for all these 4 minutes there will be a connection between your HttpClient and web server.