关于nservicebus:有条件启动Saga

Conditionally start Saga

我有两种类型的事件:

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

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

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

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

  • 检查此人是否在数据库中
  • 如果是,那么只需进行更新
  • 如果不是,则开始 saga 并等待 PersonChanged 事件(假设它是一个新人)
  • 在 PersonChanged 事件中,我需要将人员插入数据库,找到 saga 并再次运行 PersonAddressChanged 的??处理程序。

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


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

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

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


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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    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; }
    }


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

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

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

    到再次重新处理时,PersonChanged 事件已经处理完毕,一切正常。