2

我有两种类型的事件:

  • 人已改变
  • 人员地址已更改。

当一个新的人(和一个新地址)被创建(创建或更新的种类)时,它们也会被发布。

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

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

  1. 检查此人是否在数据库中
  2. 如果是,那么只需进行更新
  3. 如果不是,则开始 saga 并等待 PersonChanged 事件(假设它是一个新人)

在 PersonChanged 事件中,我需要将人员插入数据库,找到 saga 并再次运行 PersonAddressChanged 的​​处理程序。

我可以通过 NServiceBus Sagas 实现这一目标吗?我不能假设消息处理应该是有序的,PersonChanged → PersonAddressChanged因为有时任何特定地址更改都不会出现 PersonChanged 事件。

4

3 回答 3

2

可以用 sagas 做到这一点,是的,虽然你可能不应该这样做。首先,在创建和更新人员时使用相同的事件会丢失事件中的语义信息(这是您试图通过检查数据库中的用户来重新创建的内容)。你也会让自己暴露在很多潜在的竞争条件下,并且需要考虑如何处理它们。我的建议是重新设计您的消息流,这可能会使您当前的问题消失。

但是,如果你想尝试一下,你会做这样的事情:(未经测试或编译,只是概念代码)

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; }
}
于 2014-03-04T09:58:45.003 回答
2

我同意@carlpett 关于重新思考围绕您的活动的一些语义的声明。

我还建议您考虑与这里的传奇不同的解决方案。

如果您的 PersonAddressChanged 消息处理程序,当它发现数据库中没有当前人员时,只是去创建一个具有它获得的地址的人呢?

于 2014-03-04T16:03:45.800 回答
1

如果PersonAddressChanged事件只发送给现有的人,我根本不会为 sagas 烦恼。

相反,我会依靠重试逻辑来处理乱序到达的消息。

任何时候PersonAddressChanged处理它,它都可以假定存在人员记录。如果没有(即消息被乱序处理),则处理程序抛出异常并稍后重试。

当它再次被重新处理时,PersonChanged事件已经被处理并且一切都很好。

于 2014-03-05T08:43:24.940 回答