【问题标题】:Event Sourcing command or event from external system?事件溯源命令或来自外部系统的事件?
【发布时间】:2012-08-06 22:49:11
【问题描述】:

在大多数情况下,我理解 CQRS + ES 系统中命令和事件之间的区别。但是,有一种情况我想不通。

假设我正在构建一个个人财务跟踪系统,用户可以在其中输入借项/贷项。显然,这些是命令,一旦它们被验证,域模型就会更新并发布一个事件。但是,假设贷记/借记信息也直接来自外部系统,例如用户的花店发送一条消息,说明他已经从用户的信用卡中收取了他经常性的母亲节送货费用。在这种情况下,消息看起来像是一个事件(收费已经发生),但消息可能格式不正确并被拒绝。那么它真的是一个命令吗?但是接下来需要一种发送 ACK/NACK 的方法,但这里不是这种情况(花店只有在知道借记发生后才发送消息)。

编辑:澄清一下,我不是在谈论知道我的事件和/或命令的任何外部系统。我有一个组件从外部系统接收数据,然后必须发布事件或发送命令。问题是,我的组件应该使用哪个事件或命令?

【问题讨论】:

    标签: cqrs event-sourcing


    【解决方案1】:

    这是有界上下文的完美示例。

    在另一个系统(或有界上下文)中发生的表示相同或业务流程步骤的事件不应被视为已在接收系统中发生的事件。

    花店系统借记事件的结构可能与财务跟踪系统中发生的借记事件的结构不同。

    为了解决这个问题,我将有一个端点来监听花店系统事件,然后我会让财务跟踪系统根据事件中的信息发出命令,并可能将它与财务跟踪系统中的信息结合起来如果需要的话。发生这种情况的地方可以被认为是财务跟踪系统的客户,或者如果你愿意的话,甚至可能是“域服务”。

    在这种特殊情况下,来自 Florist 系统的事件与 Florist 系统中发生的交易信息一起出现(有界上下文)。我不会在域服务中做出任何决定,而是向做出决定的财务跟踪系统域发出命令,并且可能会发出财务跟踪系统事件。如果 Florist 系统事件在 Finance Tracking System 中出现格式错误,您可能不想以 Request/Response 或 Ack/Nack 的方式告诉 Florist 系统。该事件是从 Florist 发布的,如果您实现类似的东西,您将破坏消息传递模式。您的消息传递基础架构应该允许您重试消息,甚至修复接收代码并使用新代码重试消息。

    但是,如果您确实需要回传 Florist 有界上下文,则 Florist 系统可以订阅来自 Finance Tracking System 的事件,以查明交易是否已成功处理。只有在主系统决定交易是否发生时才需要这样做。

    如果您描述的财务跟踪系统更像是一个交易日志,您唯一需要做的就是不要将花店事件视为财务跟踪系统事件。在发出导致财务跟踪系统事件的命令之间添加一些内容。

    编辑:

    作为对您的编辑的回应。您接收组件应将命令发送到 Finance Tracking System 域,该域又会发出事件(像往常一样)。

    【讨论】:

    • 感谢 Mikael,这是一个很好的答案。有界上下文是我所缺少的。
    【解决方案2】:

    我在想同样的事情时发现了这个问题。

    我喜欢 Mikael 的回答并投了赞成票。但是,我在 DDD/CQRS 论坛上找到了另一个采用不同方法的答案,所以我想我会在这里发布给其他正在寻找的人。

    Here's a quote from Greg Young 关于跟踪外部状态的类似问题:

    在大多数库存系统中没有命令。

    或者换个说法:

    专门跟踪外部状态的系统将没有命令。

    让我们回顾一下,根据这个想法,您的系统可能会如何发展(我们还假设您不是为自己构建它):

    • 您决定创建一个个人财务跟踪器,用于记录来自外部世界的交易、显示图表、汇总总计等。
    • 因为事件是用于跟踪状态变化,而不是命令,所以您需要记录这些。您还可以在事件处理程序中编写预测,以将事件聚合为总数和图形数据点。
    • 然后你得到用户。他们称赞该应用程序,但使用率仍然很低。深入挖掘后,您会发现他们仍然使用其他应用程序来跟踪财务状况,例如,本地卡片商店没有用于定期母亲节卡片的 API,他们想将外部交易“拆分”为多个,他们的银行没有在线访问、他们想要追踪现金等。
    • 因此您添加了用户输入的交易。为此,您可以添加跟踪用户输入事务的命令。现在我们与您的问题处于同一系统。

    请注意,此变体同时接受命令和事件。您不会因为您现在允许用户更改内容而返回并将所有现有事件转换为命令。相反,您有一个系统可以接受外部事务事件、用户输入事务的命令和事务更正(创建修改 internal 状态的事件),以及将这些内部和外部事件结合起来以显示在应用程序。

    不过我很好奇。事后看来,接受的答案最终是否是一个好方法?还是像 Greg 建议的那样直接记录和处理来自花店的事件会更好?

    【讨论】:

    • 这对我来说很有意义。例如,在我的场景中,我有电子邮件跟踪事件(打开、点击等),我真的不想将其转换为命令,它们已经发生了,我只想接收。
    猜你喜欢
    • 2022-09-24
    • 1970-01-01
    • 1970-01-01
    • 2020-07-12
    • 1970-01-01
    • 1970-01-01
    • 2021-10-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多