InstanceContextMode, ConcurrencyMode, and Server-side Threading

When trying to write a scalable web service, you need to be aware of a few properties that affect how the WCF runtime will dispatch requests to your service: InstanceContextMode and ConcurrencyMode. In a nutshell, InstanceContextMode controls when a new instance of your service type is created, and ConcurrencyMode controls how many requests can be serviced simultaneously. The default InstanceContextMode is InstanceContextMode.PerSession, and the default ConcurrencyMode is ConcurrencyMode.Single.

Others have covered the details of these two knobs in detail, you can check them out for more background. Here I’m simply going to explain the affect these settings can have on your threading behavior.

If you have set ConcurrencyMode == ConcurrencyMode.Single, then you don’t have to worry about your Service instances being free-threaded (unless you are doing concurrent code within your methods). The only time multiple calls are allowed is when there are multiple instances. For InstanceContextMode.Singleton, you will get one method call at a time since you only have a single instance. For InstanceContextMode.PerCall or PerSession, ServiceModel will spin up extra threads up to a throttle in order to handle extra requests. There’s one possibly unexpected twist here. That is, when using a session-ful binding there will only be one outstanding instance call per-channel. Even with InstanceContextMode.PerCall. This is because WCF strictly maintains the in-order delivery guarantees of the channel with ConcurrencyMode.Single. So when using a session-ful binding (i.e. the default NetTcpBinding or NetNamedPipeBinding) + ConcurrencyMode.Single, InstanceContextMode.PerCall and InstanceContextMode.PerSession will behave the exact same way from a server-side threading/throttling perspective with regards to a single channel.

ConcurrencyMode == ConcurrencyMode.Reentrant is similar, except you can trigger another call to your instance from within your service (let’s say you call into a second service who calls back into you before it returns).

When you have ConcurrencyMode == ConcurrencyMode.Multiple, threading comes heavily into play. WCF will call into your instance on multiple threads unless you are using InstanceContextMode.PerCall. Throttles again will come into play (that’s a topic for another post).

To summarize, here are some basic scenarios for what happens when 100 clients simultaneously hit a service method:

Scenario 1: InstanceContextMode.Single+ConcurrencyMode.Single
Result: 100 sequential invocations of the service method on one thread

Scenario 2: InstanceContextMode.Single+ConcurrencyMode.Multiple
Result: N concurrent invocations of the service method on N threads, where N is determined by the service throttle.

Scenario 3:InstanceContextMode.PerCall+Any ConcurrencyMode
Result: N concurrent invocations of the method on N service instances, where N is determined by the service throttle

10 thoughts on “InstanceContextMode, ConcurrencyMode, and Server-side Threading

  1. Sri Vasan

    Hi Kenny,
    I have a question about host headers in IIS. When I host a wcf service on a website with multiple host headers. it fails with the following error ” This collection already contains an address with scheme http. There can be at most one address per scheme in this collection. “. Can you pls explain what is the reasoning behind this limitation?
    thanks

    Reply
  2. Greg

    I’ve got a WCF service that uses net.msmq, and I’ve set InstanceContextMode = Single. I have multiple servers watching the same queue, and noticed something strange. If my client makes 4 requests, and I have two servers, each of them will take 2 requests. But the first request takes longer than the other 3 combined. What I’ve got is one server that finished its two requests quickly, and one server that slowly works on its first request, and finally the second. Meanwhile, the other server could have completed the final request, but was unable to since it was popped off the queue.

    Client: queue a job that takes 20 seconds
    Client: queue 3 jobs that take 5 seconds each

    Server1: process 20 second job
    Server2: process 5 second job
    Server2: process 5 second job
    Server1: process 5 second job

    Total time: 25 seconds, when it could have optimally completed in 20 seconds.

    It seems to me if I say InstanceContextMode = Single, each server should only claim one job, complete that, and then see if there is more work to do.

    Reply
  3. Kenny

    Sri, this is a known limitation of WCF v1. Basically if you specify multiple bindings for the same protocol in IIS for the same web site, we will automatically generate multiple base addresses for the same protocol. However, when we pass the list of addresses to ServiceHost constructor, it throws the error that you indicated in your email below. The reason is that ServiceHost uses the protocol as the key for the BaseAddresses collection. This has been fixed in Orcas.

    Reply
  4. Kenny

    Greg, can you try setting MaxConcurrentCalls to 1? With WCF throttles, we will often read ahead and so while we’re processing a single message, another one will get queued up….

    Reply
  5. Pingback: kennyw.com » Blog Archive » Throttling in WCF

  6. Oskar

    Hi Kenny,

    Your blog came up on a google search I did, I hope you can help me.

    When hosting a service in IIS, how does WCF choose the base address? If I surf the service behind the firewall, I get http://[computername]/MyService/Service.svc in the import schema links in the wsdl AND if I’m outside the firewall I get the same internal links.

    Because of this it is not possible to use svcutil to create the client because the computer name is of course not know outside the firewall. If I add the external IP as the host header it works, but that will not be possible in this scenario. And if I have two host headers I get the error described by Sri above.

    Is there a solution to this problem?

    Thank you,
    Oskar

    Reply
  7. Kenny

    Oskar, the base address is chosen by your vdir settings in IIS. Do you not have a publicly consumable DNS name?

    Reply
  8. Pingback: Throttling in WCF « Bhavin Patel

  9. Chris B.

    Thanks for this article — still helpful 3+ years on. In particular, this little gotcha had me hooked:

    “There’s one possibly unexpected twist here. That is, when using a session-ful binding there will only be one outstanding instance call per-channel. Even with InstanceContextMode.PerCall. This is because WCF strictly maintains the in-order delivery guarantees of the channel with ConcurrencyMode.Single.”

    Thanks again for the help.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *