I have been writing a lot of code using the Groove Web Services Helpers that follows this pattern:
· Event Thread: periodically invoke a Groove Web Service (GWS) Operation to poll a Groove event queue for Groove events and raise events locally that represent the event (data) from Groove.
· Main thread: respond to events from Event Thread and invoke GWS operations to do stuff
So, every 5 seconds the Event Thread code reads an event queue. Occasionally the read returns data that represents events that happened in Groove. The Event Thread code raises a “real” event locally. The Main Thread reacts to the event and invokes more GWS operations that read or write data from a Groove tool.
I’ve been troubled by the behavior of the code – sometimes web service operations fail (with a message like “The request was aborted: The request was cancelled”), or take a long time to complete, and it’s not clear why. I finally stumbled across a description of a problem that seemed pertinent and that suggested a solution.
The problem seems to go like this. Web Service connections are re-used by default – this benefits efficient use of a physical link. A connection that is idle for too long or that has timed out is terminated by a FIN or finish signal which can be sent by either client or server end. The problem is that the FIN signal from one end can essentially pass by a legitimate packet from the other end like ships passing in the night. I can’t go much further with this discussion, other than to say that when this happens, it seems to get mishandled, one side uses a connection that the other side terminated, and this leads to web service operations failing unexpectedly. This appears to be especially true when the web service client and server are running on the same PC – as happens with Groove Web Services. Groove is a web services server and the applications that I write consume Groove Web Services and run on the same box as Groove. The situation is likely aggravated by the heavy use of the CPU resource.
Now the good news… I tried the solution that was suggested and it seems to work. I’ve added the solution to the Groove Web Services Helpers and will republish them shortly, after I’ve done some more testing. For the record, the solution I implemented is to add the following code to a static constructor for the Context object:
static Context()
{
System.Net.ServicePointManager.MaxServicePointIdleTime = 5000;
System.Net.ServicePointManager.DefaultConnectionLimit = 24;
}
The use of a static constructor is interesting. A static constructor, also called a Type constructor, initializes a type. The CLR calls a static constructor before the first instance of that type is created or any static members are accessed (Cwalina and Abrams, Framework Design Guidelines, 2007).
This means that the two properties of ServicePointManager are set before a web service client application can construct a GWS Helpers Context object. That’s the behavior I needed – to get these defaults set on the web services protocol stack before the client uses any Groove web services.
The downside is that these settings apply to all web service operations, regardless of the target. Another problem is that I honestly can't say I understand why making these settings would fix the problem. But, I'm not going to argue with success, and they do appear to work.
It’s possible to set a connection limit on a specific URI, using the following XML in app.config:
<system.net>
<connectionManagement>
<add address="http://localhost:9080" maxconnection="24"/>
</connectionManagement>
</system.net>
But I couldn’t see any way to set the max idle time. So I made the change to the code and I’m testing it. I will say that it seems to really fix a lot of problems I was seeing, so I’m hopeful that this fix will be very beneficial to apps that make repeated calls to web service operations.