locked
Race condition with content-based correlation (or How to implement a Duplex Contract) RRS feed

  • Question

  • I just spent a while trying to see why I had inconsistent behavior in my workflow which would work the first time, but not the second or third. I have found that it's a problem with the way I'm using content-based correlation as there is a race between the correlation initialization and receiving the message from the other service.

    If everything worked properly, I would have something like:
    1. WF1 calls WF2 which returns a job id
    2. WF1 waits on a Receive looking for that job id in a message
    3. WF2 calls WF1 with the job's result (has the job id in that message)
    4. WF1 receives the message and does further processing

    My workflows look like this:
    Workflow 1 = new Sequence
    {
    ...
      new Send(),
      new ReceiveReply() // CorrelationInitializer = new QueryCorrelationInitializer (on job id in body)
      new Receive // CorrelatesOn = new MessageQuerySet (on job id in body)
    ...
    }

    Workflow 2 = new Sequence
    {
      new Receive(),
      new SendReply() // returns a job id in the message body
    ... // processing
      new Send() // calls the original caller with job id in the message body
    }

    The problem I'm seeing is that when WF2's processing is really fast, the message from it's last Send is not recognized by WF1's service host (UnknownMessageReceived). I believe this is because the correlation on WF1 has not yet initialized/registered. Because the SendReply in WF2 is a one-way, the second Send is actually being sent to WF1 while WF1 is still processing the initial reply from WF2. If I put a 1 second delay in WF2 after SendReply, everything works fine.

    If this were pure WCF, my services could be described with contracts like:

    [ServiceContract(... CallbackContract = typeof(IWF2Client))]
    interface IWF2
    {
      Guid Run(...);
    }

    [ServiceContract(...)]
    interface IWF2Client // implemented by WF1's last Receive
    {
      OnComplete(Guid id, ...);
    }

    I'm wondering how I should be doing this because obviously my current solution is not working. 

    Has anyone else tried this sort of callback pattern with workflow services? Could I get some guidance from the WF team? I guess when you boil it down, I'm basically looking to implement a Duplex contract in WF

    Many thanks!
    Tuesday, March 9, 2010 4:49 AM

All replies