If a WCF service internally connected to a legacy system which does not support multi threading, the WCF needs to be throttled.
The easiest way to achieve this is to make the WCF works sequentially by setting this up not to work concurrently.
By default, a WCF configured to process in multiple instances and concurrency mode. Before setting up the throttle in WCF, it is important to understand how concurrency works in WCF.
Two columns below are great to understand this.
Three ways to do WCF instance management
WCF Concurrency (Single, Multiple, and Reentrant) and Throttling
In a nutshell, it is easy to manage concurrency in WCF. It can be configured in serviceBehaviors section of web.confing.
<serviceBehaviors> <behavior name="serviceBehavior"> <serviceThrottling maxConcurrentCalls="16" maxConcurrentSessions="10" maxConcurrentInstances="2147483647" /> </behavior> </serviceBehaviors>
In my case, I needed to make this WCF accept the client request as fast as it can, but had to call the back-end process in a given interval.
To accomplish this, I changed the configuration as below.
<serviceBehaviors> <behavior name="serviceBehavior"> <serviceThrottling maxConcurrentInstances="1" /> </behavior> </serviceBehaviors>
This configuration means the WCF will have only a single instance. However, by default, this WCF can have multiple threads working on concurrency.
The basic idea to throttle is having a static variable that can work as a gate keeper.
public class Throttle : IThrottle { public static DateTime staticTime; DoWork() { // do something } while (true) { if (DateTime.Now - westpaccws.staticTime > TimeSpan.FromMilliseconds(300)) { westpaccws.staticTime = DateTime.Now; break; } } DoThrottledWork() { // do something else that needs to be throttled. } }
In this example, the static varialbe ‘staticTime’ is shared by all threads. Only after 0.3 seconds has passed, a thread can proceed to the next step. The static variable must be defined in the main class of the service. Otherwise, the static variable will not work as we expected.
This looked like working at first. But, not really. In some cases, multiple threads accessed the staticTime at the same time and each one decided that it’s good to go.
So, I had to add lock around time checking routine.
public class Throttle : IThrottle { public static DateTime staticTime; public static Object lockthis = new object(); DoWork() { // do something } while (true) { lock (lockthis) { if (DateTime.Now - westpaccws.staticTime > TimeSpan.FromMilliseconds(300)) { westpaccws.staticTime = DateTime.Now; break; } } } DoThrottledWork() { // do something else that needs to be throttled. } }
This works well for me as I have only one WCF installed in the server.
If this will be put on the load balanced environment, the static variable may need to be changed to something else, such as a separate windows service.