我有两种类型的事件:
当创建新的Person(和新地址)时(创建或更新的类型),它们都会被发布。
创建新人时会发布两个事件:PersonChanged和PersonAddressChanged(按此顺序)。但是,因为NServiceBus
是异步的,所以可以按任何顺序处理它们。当地址被更改时(对于现有人),没有PersonChanged事件,只有PersonAddressChanged事件。
我想为PersonAddressChanged事件编写一个处理程序:
在PersonChanged事件中,我需要将人员插入数据库,找到saga并再次运行PersonAddressChanged的处理程序。
我能用NServiceBus Sagas实现这个目标吗?我不能假设消息处理应该按顺序PersonChanged → PersonAddressChanged
,因为有时候任何特定地址更改都不会有PersonChanged事件。
答案 0 :(得分:2)
我同意@ carlpett关于重新思考你事件的一些语义的声明。
我还建议你考虑一个不同于解决方案的解决方案。
如果您的PersonAddressChanged消息处理程序在看到数据库中没有当前人员时,只是去创建一个包含其地址的消息处理器怎么办?
答案 1 :(得分:1)
你可以用传奇来做这件事,是的,尽管你可能不应该这样做。首先,在创建和更新人员时使用相同的事件会丢失事件中的语义信息(这是您尝试通过检查数据库中的用户来重新创建的)。你也暴露了很多潜在的竞争条件,需要考虑如何处理它们。我的建议是重写你的消息流,这可能会使你当前的问题消失。
但是,如果你想尝试它,你会做这样的事情:(没有测试或编译,只是概念代码)
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; }
}
答案 2 :(得分:1)
如果仅为现有人发送PersonAddressChanged
事件,我根本不会打扰传奇。
相反,我依靠重试逻辑来处理无序到达的消息。
每次处理PersonAddressChanged
时,都可以假定存在人员记录。如果没有(即消息正在按顺序处理),则处理程序抛出异常并稍后重试。
当它再次被重新处理时,PersonChanged
事件已被处理,一切都很好。