This post discusses several questions:
- Should ‘PerCall’ services care about the concurrency mode?
- Can closing the channel block after calling O/W operation?
- Should you reuse the same proxy instance concurrently?
- Does the Async Pattern matter in concurrent client?
This is quite a long post, but it should be quite interesting , you should download the example here.
In order to discuss the matter, let’s establish the scenarios we’re going to test first:
About the contract:
About the service:
- The implementation of the service doesn’t matter, let’s make it simulate work using Thread.Sleep for 5 seconds.
- The service is configured as PerCall
About the binding:
- Standard NetTcpBinding
About the client:
- The client works with a contract with the addition of the asynchronous pattern operations (Begin/End)
- The client makes 2 concurrent requests to the service on the same channel using a certain invocation mode. (see further down)
- It closes the channel once both calls are completed
About the invocation modes:
The findings vary according to how you call the service.
Let’s define 4 modes – RequestReply, RequestReplyAsync, OneWay, OneWayAsyncPattrn.
Typically, the implementation describes it pretty straightforward –
The variations for the scenarios are made with every combination of the service concurrency level and invocation mode.
That’s it, so how about some answers?
Note – I suggest you download the example and see the scenarios in action.
First of all, some of the findings occur due to the selection of the binding.
NetTcpBinding creates a duplex session channel shape by nature, it doesn’t matter if the service is PerSession or not, that is why other bindings might result with different behavior.
Q: Should ‘PerCall’ services care about concurrency?
In Short: Yes!
The ConcurrencyMode is often described as a concurrency control in the access to the service instance.
If that was the case, PerCall services shouldn’t behave differently according to the ‘ConcurrencyMode’ you set on it, since every call gets a dedicated instance.
So, is that the case? No
Try using the ‘OneWay’ invocation mode and see the differences between concurrency mode ‘Single’ and ‘Multiple’.
– Using ‘Single’ ends up with the two calls being invoked sequentially on the service side, causing the channel to be closed after 10 seconds.
– Using ‘Multiple’ ends up with the two calls being invoked concurrently on the service side, the channel is then closed after 5 seconds.
There we go, using this scenario we see that you should consider setting the concurrency mode of your services, even if it’s PerCall.
Another thing to note here is that closing the operation can block, as we see here, and can throw exceptions too.
Q: Can closing the channel block after calling O/W operation?
As seen in the same scenario as above – Yes!
Due to the session-ful duplex channel shape the NetTcpBinding creates, closing the channel waits for the operation to be completed to gracefully terminate the connection.
Another tip here is you can use the OneWayBindingElement which basically removes the session-bound channel shape, and then you can close it without waiting for the O/W operation to complete.
Q: Does the Async Pattern matter in concurrent client?
In Short: Yes!
Try setting the ConcurrencyMode to Multiple and examine the difference between the invocation mode ‘RequestReply’ and ‘RequestReplyAsyncPattern’,
When calling a R/R operation in its synchronous form from concurrent environments, it isn’t really dispatched concurrently on the service.
Actually, it is being dispatched sequentially one after another.
Oddly enough, if you use the asynchronous pattern invocation, it is dispatched concurrently on the service side!
Q: Should you reuse the same proxy instance in a concurrent environment?
In Short: It Depends
First of all, ‘PerSession’ or Duplex services are out of the question in this case, as they may require a specific design of using them.
As you can see from the example above, when using the same proxy instance concurrently, it doesn’t assure you it is actually processed concurrently on the service.
This basically means that concurrent calls can be queued up and cause a bottleneck and eventually blow up entirely.
Additionally, various tests we made at several customers showed that even if you manage to configure it as efficient as possible, where everything is being processed concurrently at both ends, intensive use of the same channel concurrently can cause an overload and turn the performance to the worse.
The above basically indicates that you shouldn’t use the same instance concurrently.
However, you might find that using the same channel gets you better performance at specific loads, especially if you build infrastructure to separate the processing layer from the WCF runtime.
To conclude the matter, you should assess the expected load and choose the right approach for your needs.