I have two types of events :
Both of them are being published also when a new Person (and a new address) is created (kind of create or update).
When a new person is created two events are published: PersonChanged and PersonAddressChanged (in that order). However, because NServiceBus
is asynchronous they can be handled in any order. And when an address is changed (for an existing person) there is no PersonChanged event, only PersonAddressChanged event.
I want to write a handler for PersonAddressChanged event which will :
And in PersonChanged event I need to insert the person to database, find the saga and run the handler for PersonAddressChanged once again.
Can I achieve this with NServiceBus Sagas? I cannot assume that the message processing should be in order PersonChanged → PersonAddressChanged
because sometimes there will be no PersonChanged event for any particular address change.
You could do this with sagas, yes, although you probably shouldn't. First of, having the same event for both creation and updating the person loses semantic information in the event (which is what you are trying to recreate by checking for the user in the database). You also expose yourself to a lot of potential race conditions, and need to think about how to handle them all. My suggestion would be to rework your message flow, that will probably make your current problem go away.
But, if you want to try it anyway, you'd do something like this: (not tested or compiled, just conceptual code)
public class MySaga : Saga<MySagaDataType>, IAmStartedByMessage<PersonChanged>, IAmStartedByMessage<PersonAddressChanged> {
public override void ConfigureHowToFindSaga() {
// How to correlate PersonChanged and PersonAddressChanged messages
}
public void Handle<PersonChanged>(PersonChanged msg) {
Insert(msg);
if(Data.PendingAddressChange != null)
UpdateDatabase(msg);
MarkAsComplete();
}
public void Handle<PersonAddressChanged>(PersonAddressChanged msg) {
if(IsInDatabase(msg.Person)) {
UpdateDatabase(msg);
MarkAsComplete();
}
else {
Data.PendingAddressChange = msg;
}
}
}
public class MySagaDataType : IContainSagaData {
public PersonAddressChanged PendingAddressChange { get; set; }
}