How to design a NServiceBus Saga started by receipt of multiple messages

564 Views Asked by At

I am trying to find help on designing a Saga in NServiceBus 5.x that is started by 2 or more messages. This means that the saga will not start with a single message, but all messages must be present before the saga starts.

I don't quite understand how that would work, and there are no samples or examples to be found anywhere.

I read a couple of books that clearly state it's perfectly fine to have a saga started by several messages.

What I don't get is how the saga is found when you need e.g. 3 messages to start the saga. All 3 messages have to arrive, in any order, before the saga can "start". How does this affect my choice of the [Unique] attribute?

Example: I need saga that is "unique"ly identified by three IDs "StoreID", "ComputerID", "UserID". Those three IDs would arrive in three distinct commands, Message1, Message2, Message3.

public class MySaga : Saga<MySagaData>, 
IAmStartedByMessages<Message1>, 
IAmStartedByMessages<Message2>, 
IAmStartedByMessages<Message3>
{ ...
}

Should MySagaData have the [Unique] attribute on three properties?

public class MySagaData
{
    [Unique]
    public int StoreId {get;set;}
    [Unique]
    public int ComputerId {get;set;}
    [Unique]
    public int UserId {get;set;}
}

Or do I have to create readonly property concatenating those three?

When Message1 and Message3 arrive, the saga can't be started. Message2 is missing.

Then another Message1 arrives.

Then Message2 arrives. (completing the first saga, so it can be started)

What about the second Message1?

How would this be handled?

3

There are 3 best solutions below

2
tom redfern On

Sagas do not support the pattern you are describing. IAmStartedByMessages directives are applied with an ANY, rather than ALL, semantic.

Broadly, you have two options;

  1. Start your saga instance with one of the required messages and then just handle the arrival of the others as and when they are sent, or
  2. Implement either the Aggregator or Observer pattern at some point before your saga is called, which will obviously remove the requirement to wait for multiple messages.
0
Adam Fyles On

It sounds to me like the act of starting the saga is a saga. What if you created a saga to manage the collection of the messages and then start a different one to do whatever work is pending the arrival of those messages.

1
Bob.Langley On

Every message handled by your Saga implementation received will belong to only 1 instance of that Saga. You will still need some way in each of those 3 messages to correlate them to the same Saga instance.

I would re-look at your process and see what it is that binds any three combinations of those 3 entities together to find what uniquely identifies the Saga, e.g. Order.

After this your Saga can just wait until it receives all 3 messages to start doing whatever it is you want to do by checking that all three of those IDs are set before doing whatever it is the Saga needs to do.