A while ago I came across an interesting article explaining that putting HttpClient
in a using block will dispose of the object when the code has executed but not close the TCP socket and the TCP state will eventually go to TIME_WAIT and stay in that state listing for further activity for 4 minutes (default).
So basically using this multiple times:
using(var client = new HttpClient())
{
//do something with http client
}
results in many open TCP connections sitting in TIME_WAIT.
You can read the whole thing here:
You're using HttpClient wrong and it is destabilizing your software
So I was wondering what would happen if I did the same with the ClientBase<TChannel>
derived service class created by Visual Studio when you right-click a project and select add Add Service Reference . . and implemented this:
//SomeServiceOutThere inherits from ClientBase
using (var service = new SomeServiceOutThere())
{
var serviceRequestParameter = txtInputBox.Text;
var result = service.BaddaBingMethod(serviceRequestParameter);
//do some magic (see Fred Brooks quote)
}
However, I haven't been able to recreate exactly the same behavior, and I wonder why.
HttpClient
demo (even when passing different parameters to the service, but keeping the app running).It seems that WCF is smart enough to realize there is already an established connection to the server, and uses that.
The interesting part is that, when I repeated the process above, but stopped and restarted the application between each call to the service, I did get the same behavior as with HttpClient
:
There are some other potential problems with ClientBase
(e.g. see here), and I know that temporarily open sockets may not be an issue at all if traffic to the service is relatively low or the server is setup for a large number of maximum connections, but I would still like to be able to reliably test whether this could be a problem or not, and under what conditions (e.g. a running windows service hitting the WCF service vs. a Desktop application).
Any thoughts?
WCF does not use HttpClient
internally. WCF probably uses HttpWebRequest
because that API was available at the time and it's likely a bit faster since HttpClient
is a wrapper around it.
WCF is meant for high performance use cases so they made sure that HTTP connections are reused. Not reusing connections by default is, in my mind, unacceptable. This is either a bug or a design problem with HttpClient
.
The 4.6.2 Desktop .NET Framework contains this line in HttpClienthandler.Dispose
:
ServicePointManager.CloseConnectionGroups(this.connectionGroupName);
Since this code is not in CoreClr there is no documentation for it. I don't know why this was added. It even has a bug because of this.connectionGroupName = RuntimeHelpers.GetHashCode(this).ToString(NumberFormatInfo.InvariantInfo);
in the ctor. Two connectionGroupName
s can clash. This is a terrible way obtaining random numbers that are supposed to be unique.
If you restart the process there is no way to reuse existing connections. That's why you are seeing the old connections in a TIME_WAIT
state. The two processes are unrelated. For what the code in them (and the OS) knows they are not cooperating in any way. It's also hard to save a TCP connection across process restarts (but possible). No app that I know of does this.
Are you starting processes so often that this might become a problem? Unlikely, but if yes you can apply one of the general workaround such as reducing TIME_WAIT
duration.
Replicating this is easy: Just start 100k test processes in a loop.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With