有条件地开始传奇

时间:2014-03-04 08:08:56

标签: nservicebus saga

我有两种类型的事件:

  • PersonChanged
  • PersonAddressChanged。

当创建新的Person(和新地址)时(创建或更新的类型),它们都会被发布。

创建新人时会发布两个事件:PersonChanged和PersonAddressChanged(按此顺序)。但是,因为NServiceBus是异步的,所以可以按任何顺序处理它们。当地址被更改时(对于现有人),没有PersonChanged事件,只有PersonAddressChanged事件。

我想为PersonAddressChanged事件编写一个处理程序:

  1. 检查此人是否在数据库中
  2. 如果是,则只需进行更新
  3. 如果没有则启动saga并等待PersonChanged事件(假设它是一个新人)
  4. 在PersonChanged事件中,我需要将人员插入数据库,找到saga并再次运行PersonAddressChanged的处理程序。

    我能用NServiceBus Sagas实现这个目标吗?我不能假设消息处理应该按顺序PersonChanged → PersonAddressChanged,因为有时候任何特定地址更改都不会有PersonChanged事件。

3 个答案:

答案 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事件已被处理,一切都很好。