Nservice bus saga ordering

579 views Asked by At

I have two saga's namely a client saga and a client billing saga.

 public class ClientSagaState:IContainSagaData
    {
        #region NserviceBus
        public Guid Id { get; set; }
        public string Originator { get; set; }
        public string OriginalMessageId { get; set; }
        #endregion

        public Guid ClientRef { get; set; }

        public ClientMessage ClientChangeMessage { get; set; }

        public ClientContactChangeMessage ClientContactChange { get; set; }


    }

      public class ClientBillingSagaState:IContainSagaData
    {
        #region NserviceBus
        public Guid Id { get; set; }
        public string Originator { get; set; }
        public string OriginalMessageId { get; set; }
        #endregion

        public Guid ClientRef { get; set; }

        public Guid FunderRef { get; set; }

        public Guid ClientBillingRef { get; set; }

        public ClientBillingMessage ClientBillingMessage { get; set; }


    }

     public  class ClientSaga:Saga<ClientSagaState>,
     IAmStartedByMessages<ClientChangeMessage>,
       IAmStartedByMessages<ClientContactChangeMessage>
   {

    public override void ConfigureHowToFindSaga()
       {

           ConfigureMapping<ClientChangeMessage>(s => s.ClientRef, m => m.EntityRef);
           ConfigureMapping<ClientContactChangeMessage>(s => s.ClientRef, m => m.PrimaryEntityRef);
       }

    public void Handle(ServiceUserChangeMessage message)
       {

           if (BusRefTranslator.GetLocalRef(EntityTranslationNames.ClientChange, message.EntityRef.Value) != null)
           {

               GetHandler<ClientChangeMessage>().Handle(message);
               CompleteTheSaga();
               return;
           }
           HandleServiceUserChangeAndDependencies(message);
           //MarkAsComplete();
           CompleteTheSaga();
       }

   }

    public class ClientBillingSaga:Saga<ClientBillingSagaState>
        ,IHandleMessages<ClientChangeMessage>,
        IAmStartedByMessages<ClientBillingMessage>,
        IHandleMessages<FunderChangeMessage>
    {

        public override void ConfigureHowToFindSaga()
        {

            ConfigureMapping<ClientChangeMessage>(s => s.ClientRef, m => m.EntityRef);
            ConfigureMapping<FunderChangeMessage>(s => s.FunderRef, m => m.EntityRef);
            ConfigureMapping<ClientBillingMessage>(s => s.ClientBillingRef, m => m.PrimaryEntityRef);

        }

         public void Handle(ClientChangeMessage message)
        {
            var state = this.Data;
            if (state.ClientBillingMessage != null)
            {
                Handle(state.ClientBillingMessage);
            }
        }

          public void Handle(CareSysInvoiceLineInsertMessage message)
          {

                //First check for the funder 
                //If funder is not there store the message in saga

                //If funder is there then check for client
                //If client is not there then put the message in saga

                // if funder and client are there then execute the message delete the saga
          }


    }

Here is the scenario:

1)If i receive a ClientBillingMessage whose client and funder are not there , i store this message in saga.

2)If now the funder message comes then it gets executed , but the saga still persists as it is waiting for client message

3)Now if the client message comes it runs the ClientBillingSaga's client message handler first hence the already existing ClientBillingSaga still persists and after that it goes and executes the handler inside the ClientSaga for Client message.

My question: Is there any way i can order the execution of these two saga. I found ISpecifyMessageHandlerOrdering interface which deals with handling of messages but i don't think i can use it for saga.

2

There are 2 answers

0
Sean Farmar On

Sagas are meant to help with synchronising events over time.

You can collect the data you need form the messages you handled in your saga state and once you you have handled all then proceed to send a command/publish an event so the business logic could be processed by a handler.

Note: The actual work (business logic and domain data manipulation) should be done in a separate handler (to comply with SRP and unit of work).

hope this helps

0
Paul On

I think you should not be ordering the execution of two Sagas. Saga should be autonomous acting purely on the messages it receives, has an internal state and either sends out messages or complete. If you really want to interact with another Saga, you should be using messages(commands/events).