As with a connected service, the ConcurrencyMode
property governs concurrent
playback of queued messages. With a per-call service, all queued
messages are played at once to different instances as fast as they come
off the queue, up to the limit of the configured throttle. There is no
need to configure for reentrancy to support callbacks, because the
operation contexts can never have callback references. There is also no
need to configure for multiple concurrent access, because no two
messages will ever share an instance. In short, with a queued per-call
service, the concurrency mode is ignored.
When it comes to a sessionful queued service, you are required to
configure the service with ConcurrencyMode.Single
. The reason is that it
is the only concurrency mode that allows you to turn off
auto-completion, which is essential to maintain the session semantic. The calls in the message are
always played to the same service instance, one at a time.
A queued singleton is really the only instancing mode that has any
leeway with its concurrency mode. If the singleton is configured with
ConcurrencyMode.Single
, WCF will
retrieve the messages all at once from the queue (up to the thread pool
and throttling limits) and then queue up the calls in the internal queue
the context lock maintains. Calls will be dispatched to the singleton
one at a time. If the singleton is configured with ConcurrencyMode.Multiple
, WCF will retrieve
the messages all at once from the queue (up to the thread pool and
throttling limits) and play them concurrently to the singleton.
Obviously, in that case the singleton must provide for synchronized
access to its state. If the singleton is also transactional, it is prone
to transactional deadlocks over prolonged isolation maintained
throughout each transaction.
Queued calls have a nasty side effect of excelling at turning a low level of load into a high level of stress. Imagine an offline queued service that sustained relatively low load, such as a call per minute for one day. Once the host is launched, WCF flushes the queued calls (all 1,440 of them) to the service all at once, subjecting it to high stress. The fact that there are over 1,000 messages in the queue does not mean that your design supports 1,000 concurrent instances and calls.
Throttling a queued service is your way of controlling the
stress on the service and avoiding turning load into stress. The
important value to throttle is the number of concurrent playbacks.
This is an effective way of throttling the number of played messages,
because if the maximum number of concurrent calls is exceeded (overall
stress), the excess messages will stay in the queue. With a per-call
service, the throttle controls the overall number of allowed
concurrent instances (and their implied resource consumption). With a
per-session service, the throttle controls the number of allowed
sessions. In the case of a queued singleton, you can combine a
throttle value with ConcurrencyMode.Multiple
to control just how
many concurrent players are allowed (stress) and how many messages to
keep in the queue (buffered load).
13.58.132.97