Question about concurrency and sessions

Hello.

I've been trying to understand the interdependencies between: SessionMode, InstanceContextMode, ConcurrencyMode and the used binding.

I’ve done a systematic test where I issue two concurrent asynchronous calls over the same channel, and observed the following:

  1. With SessionMode=NotAllowed the calls are processed concurrently, independently of the InstanceContextMode (PerCall or PerSession), of the ConcurrencyMode and of the binding (NetTcpBinding throws an exception). This is ok because every call is handled by a different instance.
  2. With SessionMode=Required and InstanceContextMode=PerSession and ConcurrencyMode=Single, the calls are processed sequentially. This is ok because the instance is always the same and the concurrency mode is single
  3. With SessionMode=Required and InstanceContextMode=PerCall and ConcurrencyMode=Single, the calls are processed sequentially. This isstrange, since every call is handled by a different instance.
  4. With SessionMode=Required and ConcurrencyMode=Multiple (InstanceContextMode = PerCall or PerSession), the behavior depends on the binding:
a) WSHttpBinding: calls processed sequentially. This isstrange, since the concurrency mode is multiple.
b) NetTcpBinding: calls processed concurrently: This is ok.

Is the behavior for items 3 and 4 a) correct? What is the justification for this behavior.

I’ve made the same tests with two different channel instances and the processing is always concurrent. This is ok, since the sessions are always different, which implies that the instances are always different.

So, it appears that with SessionMode=Required

  • ConcurrencyMode = Single implies sequential processing on the same session.
  • Using WSHttpBinding implies sequential processing on the same session, independently of the ConcurrencyMode.

Are these conclusions correct? What is the explanation for this behavior?

These tests were done with the RTM version (I can send the code if needed).

Best regards
Pedro Felix
[2779 byte] By [PedroFelix] at [2008-1-10]
# 1

First, when you say "asynchronous" calls do you mean IsOneWay calls or AsyncPattern calls? If the latter, on which side: Client or service?

As to the WSHttpBinding stuff you have to realize that http is by definition two-way; services do not fire off the http response (empty, in the case of one-way) until processing has finished on the service. This holds up the channel instance. This is an implementation detail of that binding, which is why tcp doesn't work that way -- the session is a different type of session. It would work the way you expect, too, if you had a UDP channel.

RalphSquillace at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...
# 2
Hello. Thanks for the reply.
1. When I say asynchronous I was refering to AsyncPattern calls on the client side. The operation at the service is a normal synchronous operation (request-reply). I'm assuming that the client channel supports multiple concurrent requests in the same session with both WSHttpBinding and NetTcpBinding. Am I correct?

2. I don't understand why there cannot be concurrent processing when the binding is WSHttpBinding and sessions are required. I understand that the session implementation is diferent: TCP already has sessions and WSHttpBinding uses WS-ReliableMessaging or WS-SecureConversation for that purpose. What I don't understand is why the second implementation doesn't allow concurrent processing in the same session.

3. I don't understand why binding=NetTcpBinding, InstanceContextMode=PerCall and ConcurrencyMode=Single implies sequential processing in the same session. Since InstanceContextMode=PerCall, the service instances are diferent, so there could be concurrent processing

What am I missing here?

Once again, thanks for the reply
Best regards
Pedro Felix

PedroFelix at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...
# 3
I think your results sound not quite right to me... I am curious, are you explicitly calling Open() on the client channel before starting the concurrent calls? If you don't call Open() explicitly and start making concurrent calls, the 'auto-Open' feature of WCF client channels sometimes sequentializes calls while the auto-Open is still processing, and I wonder if this is interacting with your results.
BrianMcNamara-MSFT at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...
# 4
Hello.
Yes, I didn't open the channels explicitly. Due to this, the synchronous operations were always processed sequentially. That was the reason why I did these tests using the client async operations.
I've rerun my tests using a synchronous operation (non OneWay), with an explicit open, and observed the following (the '<<<' marks the "strange" cases):
NotAllowed PerCall Single BasicHttpBinding => Concurrent
NotAllowed PerCall Single NetTcpBinding => exception thrown
NotAllowed PerCall Single WSHttpBinding => Concurrent
NotAllowed PerCall Multiple BasicHttpBinding => Concurrent
NotAllowed PerCall Multiple NetTcpBinding => exception thrown
NotAllowed PerCall Multiple WSHttpBinding => Concurrent
NotAllowed PerSession Single BasicHttpBinding => Concurrent
NotAllowed PerSession Single NetTcpBinding => exception thrown
NotAllowed PerSession Single WSHttpBinding => Concurrent
NotAllowed PerSession Multiple BasicHttpBinding => Concurrent
NotAllowed PerSession Multiple NetTcpBinding => exception thrown
NotAllowed PerSession Multiple WSHttpBinding => Concurrent
Required PerCall Single BasicHttpBinding => exception thrown
Required PerCall Single NetTcpBinding => Sequential <<<
Required PerCall Single WSHttpBinding => Sequential <<<
Required PerCall Multiple BasicHttpBinding => exception thrown
Required PerCall Multiple NetTcpBinding => Concurrent
Required PerCall Multiple WSHttpBinding => Sequential <<<
Required PerSession Single BasicHttpBinding => exception thrown
Required PerSession Single NetTcpBinding => Sequential
Required PerSession Single WSHttpBinding => Sequential
Required PerSession Multiple BasicHttpBinding => exception thrown
Required PerSession Multiple NetTcpBinding => Concurrent
Required PerSession Multiple WSHttpBinding => Sequential <<<

Thanks for your help
Best regards
Pedro Felix

PedroFelix at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...
# 5
I've made a little block schema.
Tell me if what i'm writing there is correct and if not, how would you modify it?
I'm assuming certain things undocumented which should be obvious... i don't know...

I havn't done any test, i've just read documentation. And i'm not taking into account
the session mode.

Bye.

Marzullo at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...
# 6
Pedro Felix wrote:
Hello.
Yes, I didn't open the channels explicitly. Due to this, the synchronous operations were always processed sequentially. That was the reason why I did these tests using the client async operations.
I've rerun my tests using a synchronous operation (non OneWay), with an explicit open, and observed the following (the '<<<' marks the "strange" cases):
NotAllowed PerCall Single BasicHttpBinding => Concurrent
NotAllowed PerCall Single NetTcpBinding => exception thrown
NotAllowed PerCall Single WSHttpBinding => Concurrent
NotAllowed PerCall Multiple BasicHttpBinding => Concurrent
NotAllowed PerCall Multiple NetTcpBinding => exception thrown
NotAllowed PerCall Multiple WSHttpBinding => Concurrent
NotAllowed PerSession Single BasicHttpBinding => Concurrent
NotAllowed PerSession Single NetTcpBinding => exception thrown
NotAllowed PerSession Single WSHttpBinding => Concurrent
NotAllowed PerSession Multiple BasicHttpBinding => Concurrent
NotAllowed PerSession Multiple NetTcpBinding => exception thrown
NotAllowed PerSession Multiple WSHttpBinding => Concurrent
Required PerCall Single BasicHttpBinding => exception thrown
Required PerCall Single NetTcpBinding => Sequential <<<
Required PerCall Single WSHttpBinding => Sequential <<<
Required PerCall Multiple BasicHttpBinding => exception thrown
Required PerCall Multiple NetTcpBinding => Concurrent
Required PerCall Multiple WSHttpBinding => Sequential <<<
Required PerSession Single BasicHttpBinding => exception thrown
Required PerSession Single NetTcpBinding => Sequential
Required PerSession Single WSHttpBinding => Sequential
Required PerSession Multiple BasicHttpBinding => exception thrown
Required PerSession Multiple NetTcpBinding => Concurrent
Required PerSession Multiple WSHttpBinding => Sequential <<<

Thanks for your help
Best regards
Pedro Felix



I think there is something wrong in your tests.

i.e.:

1-Required PerCall Single NetTcpBinding => Sequential <<<
2-Required PerCall Multiple NetTcpBinding => Concurrent

This cannot happen, concurrency mode is not meaningful when you set PerCall so
behaviour cannot change from 1 to 2. If this change is true, the documentation is wrong.
Pease post your code.

Bye
.

Marzullo at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...
# 7
Hello:

Yes, I also think that there is something strange with my tests. I just cannot figure out what.
I'm sending the code attached to this post.

Pedro Felix

namespace Concurrency
{
[ServiceContract]
public interface IService
{
[OperationContract]
string Operation1(string s);

}

[ServiceContract]
public interface IAsyncService
{
[OperationContract(Action = "http://tempuri.org/IService/Operation1", ReplyAction = "http://tempuri.org/IService/Operation1Response")]
string Operation1(string s);

[OperationContract(AsyncPattern = true, Action = "http://tempuri.org/IService/Operation1", ReplyAction = "http://tempuri.org/IService/Operation1Response")]
System.IAsyncResult BeginOperation1(string s, System.AsyncCallback callback, object asyncState);

string EndOperation1(System.IAsyncResult result);
}

//-- Implementation
[ServiceBehavior]
class ServiceImpl : IService
{
public static volatile bool begin = false;
public static volatile bool end = false;
public string Operation1(string s)
{
if(begin == true){
if(end == true) Console.WriteLine("Sequential");
else Console.WriteLine("Concurrent");
}
begin = true;
Thread.Sleep(4000);
end = true;
return s.ToUpper();
}
}

delegate void ServiceCaller<CT>(CT channel, string s);

class Program
{
static void
RunTestCase<CT>(SessionMode sm, InstanceContextMode icm, ConcurrencyMode cm, Binding b, string address, ServiceCaller<CT> action)
{
Console.Write("{0} {1} {2} {3} => ",
sm, icm, cm, b.GetType().Name);
ServiceHost sh = new ServiceHost(typeof(ServiceImpl), new Uri(address));
sh.AddServiceEndpoint(typeof(IService), b, "ep1");
sh.Description.Endpoints[0].Contract.SessionMode = sm;
ServiceBehaviorAttribute sb = sh.Description.Behaviors.Find<ServiceBehaviorAttribute>();
if (sb == null)
{
sb = new ServiceBehaviorAttribute();
}
sb.InstanceContextMode = icm;
sb.ConcurrencyMode = cm;
try
{
ServiceImpl.begin = false;
ServiceImpl.end = false;

sh.Open();

ChannelFactory<CT> cf = new ChannelFactory<CT>(b, address + "/ep1");
cf.Endpoint.Contract.SessionMode = sm;
CT[] ch = new CT[2];
ch[0] = cf.CreateChannel();
ch[1] = cf.CreateChannel();
ICommunicationObject ico = ch[0] as ICommunicationObject;
ico.Open();
ico = ch[1] as ICommunicationObject;
ico.Open();

Semaphore sem = new Semaphore(0, 2);
for (int i = 0; i < 2; ++i)
{
int ix = i;
ThreadPool.QueueUserWorkItem(
delegate{
action(ch[0], Thread.CurrentThread.ManagedThreadId.ToString());
sem.Release();
});
}
sem.WaitOne();
sem.WaitOne();
(ch[0] as IClientChannel).Close();
(ch[1] as IClientChannel).Close();

sh.Close();

}catch(Exception exc){
Console.WriteLine("exception thrown ", exc.Message);
if(sh.State == CommunicationState.Opened) sh.Close();
}
}

static void Main(string[] args)
{
SessionMode[] sma = { SessionMode.NotAllowed, SessionMode.Required };
InstanceContextMode[] icma = { InstanceContextMode.PerCall, InstanceContextMode.PerSession };
ConcurrencyMode[] cma = {ConcurrencyMode.Single, ConcurrencyMode.Multiple};
Binding[] ba = {
new BasicHttpBinding(),
new NetTcpBinding(),
//new WSHttpBinding(SecurityMode.None,false),
new WSHttpBinding(SecurityMode.None,true)

};
string[] aa = {
"http://localhost:8080/concurrency",
"net.tcp://localhost:8080/concurrency",
//"http://localhost:8080/concurrency",
"http://localhost:8088/concurrency"
};

foreach (SessionMode sm in sma)
{
foreach (InstanceContextMode icm in icma)
{
foreach(ConcurrencyMode cm in cma){
for (int i = 0; i < ba.Length; ++i)
{

RunTestCase<IService>(sm, icm, cm, baIdea, aaIdea,
delegate(IService ch, string s) { ch.Operation1(s); }
);

/*
RunTestCase<IAsyncService>(sm, icm, cm, baIdea, aaIdea,
delegate(IAsyncService ch, string s)
{
IAsyncResult ar = ch.BeginOperation1(s, null, null);
ch.EndOperation1(ar);
}
);
*/
}
}
}
}
Console.WriteLine("press any key to exit");
Console.ReadKey();
}
}
}

PedroFelix at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...
# 8

Hello Felix.

I'm going into the same question. Why on sessionful channel, and options like Required, PerCall, Single new session wouldn't create for each call ?

Do you have an answer on your questions (and possibly on my) ?

buenohombre at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...
# 9

Hi Felix,

I tried the following scenario of configuring a service with InstanceContextMode.PerCall and implementing a sessionful contract with SessionMode.Required and I see that each call results in a new instance of the service being created, which looks like the expected behavior.

Do you see a different behavior?

Thanks

RamVenkatesan-MSFT at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...
# 10

Hi Ram

The msdn says that on sessionful channel and InstanceContextMode.PerCall a new session will be created for each incoming call, but not only a new service instance.

IMHO, Felix has mentioned that this behaviour is specific for different binding.
buenohombre at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...
# 11

Hello

It has been a while since I've though on those problems. From what I can recall, the problem was not on the instancing behavior but on the concurrency behavior. I've updated my code to show if the service is using the same instance or different instances. The results were:

NotAllowed PerCall Single BasicHttpBinding => Different instance, Concurrent
NotAllowed PerCall Single NetTcpBinding => exception thrown
NotAllowed PerCall Single WSHttpBinding => Different instance, Concurrent
NotAllowed PerCall Multiple BasicHttpBinding => Different instance, Concurrent
NotAllowed PerCall Multiple NetTcpBinding => exception thrown
NotAllowed PerCall Multiple WSHttpBinding => Different instance, Concurrent
NotAllowed PerSession Single BasicHttpBinding => Different instance, Concurrent
NotAllowed PerSession Single NetTcpBinding => exception thrown
NotAllowed PerSession Single WSHttpBinding => Different instance, Concurrent
NotAllowed PerSession Multiple BasicHttpBinding => Different instance, Concurrent
NotAllowed PerSession Multiple NetTcpBinding => exception thrown
NotAllowed PerSession Multiple WSHttpBinding => Different instance, Concurrent
Required PerCall Single BasicHttpBinding => exception thrown
Required PerCall Single NetTcpBinding => Different instance, Sequential a)
Required PerCall Single WSHttpBinding => Different instance, Sequential b)
Required PerCall Multiple BasicHttpBinding => exception thrown
Required PerCall Multiple NetTcpBinding => Different instance, Concurrent
Required PerCall Multiple WSHttpBinding => Different instance, Sequential c)
Required PerSession Single BasicHttpBinding => exception thrown
Required PerSession Single NetTcpBinding => Same instance, Sequential
Required PerSession Single WSHttpBinding => Same instance, Sequential

Required PerSession Multiple BasicHttpBinding => exception thrown
Required PerSession Multiple NetTcpBinding => Same instance, Concurrent
Required PerSession Multiple WSHttpBinding => Same instance, Sequential d)

The red lines correspond to unexpected (at least to me) behavior:

1) The instancing behavior seems to be always ok: "same instance" only happens when sessions are "Required" and InstanceContextMode is "PerSession".

2) The concurrency does not seem to be according to the specs, namely:

cenario a): the behavior should be concurrent, since the instances are different.

cenario b): as above

cenario c): the behavior should be concurrent, since the instances are different. Notice that the same scenario with NetTcpBindigs results in the expected concurrent behavior

cenario d): as above

Perhaps there is a bug hidden in my test code Sad

Pedro Felix

PedroFelix at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...
# 12

Hi Felix

IMHO you should put an additional column after "=>". That is sessionId (on sessionful channel).

And you'll see that b) scenario has same sessions for two call (although PerCall is used). I think that is reason of the same thread used.

And Felix, could you answer a question about a Callback scenario ?

If you have a time check this.

I have a service that register incoming client request and save OperationContext into some storage.

Also the service raises events to all registered clients.

Problem has occurs then client has gone (restarted)

The Service still have abandoned client a try to send a message.

How you'll solve the problem ?

buenohombre at 2007-10-3 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...

Visual Studio Orcas

Site Classified