3

I have a deadlock problem on a WCF service and I cannot understand why since every calls are synchronized on the same lock. Here is my client / service configuration.

binding="netTcpBinding"

Service Config : ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = false)

Callback Config : CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = false)

The code ( I 've simplified class and method names for clarification ):

interface ICallBack{
    void OnDoAction(string info);
}

interface IMyService{
        Report DoAction( string param);
}


public class MyClient:ICallBack{
    void OnDoAction(string info){
        Task.Factory.StartNew(() => {Console.WriteLine("Received info=["+info+"]"); });
    }

    Main(){
        MyClient client = new MyClient();
        InstanceContext context = new InstanceContext(client);
        DuplexChannelFactory<IMyService> duplexChannelFactory = new DuplexChannelFactory<IMyService>(context, "MyService");
        IMyService service =  duplexChannelFactory.CreateChannel();
        Report report = service.DoAction("Param1");
    }
}

public class MyService:IMyService{

    ICallback callback;

   public MyService(){
     callback = OperationContext.Current.GetCallbackChannel<ICallBack>();
   }

    public Report DoAction(){
        lock(callback){
            try{
                Report r = null;
                try{    
                    Log("Do action");
                    r = executeAction();
                }catch(Exception e){
                    r = new Report("Error in DoAction");
                }
                Log("Do action done");
                return report;
            }finally{
                Log("Do action has returned");
            }
        }
    }

    public void CallbackAfterDoAction(string info){
        lock(callback){
            callback.OnDoAction(info);
        }
    }
}

The call back is called in a separate thread in asynchronous way. When I call DoAction() method from my client, there is a deadlock and I have a TimeoutException:

2015-01-16 10:42:17,463 [8] ERROR - (OrderManagerViewModel.cs:311) - CancelOrder : System.TimeoutException: Cette op곡tion de demande envoyꥠ࡮et.tcp://localhost:8002/NetsOrderManagerServiceRemote/ n'a pas re赠de r걯nse dans le dꭡi imparti (00:00:05). Le temps allou顠 cette op곡tion fait peut-뵲e partie d'un dꭡi d'attente plus long. Ceci peut 뵲e d fait que le service est toujours en cours de traitement de l'op곡tion ou qu'il n'a pas pu envoyer un message de r걯nse. Envisagez d'augmenter le dꭡi d'attente de l'op곡tion (en diffusant le canal/proxy vers IContextChannel et en dꧩnissant la propri굩 OperationTimeout) et v곩fiez que le service peut se connecter au client.

Server stack trace:
ࡓystem.ServiceModel.Dispatcher.DuplexChannelBinder.SyncDuplexRequest.WaitForReply(TimeSpan timeout)
ࡓystem.ServiceModel.Dispatcher.DuplexChannelBinder.Request(Message message, TimeSpan timeout)
ࡓystem.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
ࡓystem.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
ࡓystem.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
ࡓystem.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]:
ࡓystem.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
ࡓystem.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
ࡎets.Core.API.OrderManager.Service.IOrderManager.CancelOrder(ICancelOrderRequest cancelRequest)
ࡎets.Core.Client.Wcf.OrderServiceWcfClient.RemoteOrderManagerServiceProxy.CancelOrder(ICancelOrderRequest cancelRequest) dans c:\dev\GitProjects\NetsCoreLibProject\NetsCoreLib\Nets.Core.Client.Wcf.OrderServiceWcfClient\RemoteOrderManagerServiceProxy.cs:ligne 340
ࡎets.Core.Prototype.Client.ViewModels.OrderManagerViewModels.OrderManagerViewModel.CancelOrder(Object parameter) dans c:\dev\GitProjects\NetsCoreLibProject\NetsCoreLib\Nets.Core.Prototype.Client\ViewModels\OrderManagerViewModels\OrderManagerViewModel.cs:ligne 302

The server log below show that DoAction() return before Callback execution.

Do action call log:

2015-01-16 11:13:57,342 [27] INFO - (RemoteOrderManagerService.cs:195) - CancelOrder : RemoteOrderService : CancelOrder action called by server 2015-01-16 11:13:57,342 [27] INFO - (RemoteOrderManagerService.cs:203) - CancelOrder : RemoteOrderService : CancelOrder action return report=[CancelOrder report netsd2dce|Failed to validate filter Order Consistency Check 2015-01-16 11:13:57,342 [27] INFO - (RemoteOrderManagerService.cs:208) - CancelOrder : RemoteOrderService : CancelOrder action return done

CallbackAfterDoAction call log:

2015-01-16 11:13:57,342 [EventQueue-ThreadDispatcher-HighPriorityEventQueue-2] INFO - (OrderManagerService.cs:451) - DispatchErrorOnOrder : Dispatch error on order NetsOrderId[netsd2dce] 2015-01-16 11:13:57,342 [EventQueue-ThreadDispatcher-HighPriorityEventQueue-2] INFO - (Order.cs:760) - OnCancelAck : OnCancelAck[[Order #ob_,ba3 (netsd2dce) BUY 1 [TOTF.PA] @ 47]|Owner=[]]: Cannot execute request=[CANCEL] cause Order=[[Order #ob_,ba3 (netsd2dce) BUY 1 [TOTF.PA] @ 47]|Owner=[]] is in final state=[CANCELLED] 2015-01-16 11:13:57,343 [EventQueue-ThreadDispatcher-HighPriorityEventQueue-2] INFO - (Order.cs:765) - OnCancelAck : OnCancelAck[[Order #ob_,ba3 (netsd2dce) BUY 1 [TOTF.PA] @ 47]|Owner=[]]: Call from Nets.Core.Service.Remote.RemoteOrderManagerService

BUT: When I comment the callback call on the service, the DoAction() method execute properly. It acts as if callback was called before DoAction method return when deadlock occures. I don't understand what happen since every method called are synchronized on the same lock.

PS: if I add a sleep before callback calling :

    public void CallbackAfterDoAction(){
        lock(callback){
            Thread.Sleep(3);
            callback.OnDoAction();
        }
    }

The deadlock never occures until Sleep(3) but for value < 3 ms the deadlock occures. ==> So the question is why the callback is processed before the return statement of the DoAction() method while the logs say the opposite?

  • Can you show your client code too? From your description it's not obvious to me what methods you are calling on your service on what order – Lawrence Jan 17 '15 at 01:21
  • In the code above you have DoAction() using `lock(callback)` and CallbackAfterDoAction() using `lock(MyLock)`. If they're locking different objects that could be a source of problems. – Evil Dog Pie Jan 19 '15 at 17:18
  • Just a typing error sorry. See the correct code above. – Nordine Niched Jan 19 '15 at 17:34
  • Your code is incomplete. What calls CallbackAfterDoAction? I suspect your real problem will not be shown by your fake code, because your real problem is caused by something inherent in the real code. We need a minimal WORKING example of the problem, real code that you have proven illustrates the issue... not a fictionalized version of your code that may or may not actually have the problem. – Erik Funkenbusch Jan 19 '15 at 19:48
  • Hi guyz, it was very hard for me to copy the whole code that's the reason why I didn't respond sooner. I finally found the origin of the problem. In one case the callback was called synchronously in the thread handling the client request whereas it should be executed through the event queue in asynchronous way. I've checked the code carefully following your advices. Thx for your help. – Nordine Niched Feb 05 '15 at 09:20

0 Answers0