【问题标题】:Aggregate-Root: State Change or fail with Exception or ...?聚合根:状态更改或因异常而失败或...?
【发布时间】:2014-11-01 22:15:54
【问题描述】:

Aggregate-roots 用于控制状态变化——当前允许什么,不允许什么。如果允许状态转换,请继续。如果不是,你抛出一个异常解释为什么它不被允许。

但是如果一个状态-改变没有发生,因为它已经处于请求的状态怎么办? ?

例如,如果您的聚合根上有一个Approve 方法,并且在调用它时状态已经被批准?

  • 是否应抛出异常XYZ 已获批准”?
  • 还是应该默默地忽略
  • 或者应该再次“发出信号”状态更改(事件溯源,下一段)?

在我的例子中,我使用事件溯源,因此如果发生状态更改,则会发出一个事件。在我的事件流中包含没有真正状态更改的事件对我来说并不“干净”,因为我想确信这些事件实际上是由于状态更改操作而产生的。

有经验法则吗?

编辑:
在所描述的情况下,批准一个被批准的元素并不会真正受到伤害。所以倾向于这种方式(谢谢@Eben Roux,@guillaume31)。

但让我们再添加一点香料(问题背后的实际问题):

假设:

  • 消息总线
  • 异步命令/事件处理
  • 流程管理器

如果 process-manager(又名 saga)发出命令(异步)并想知道命令是否成功,该怎么办?我认为如果流程管理器不必关心这个实施细节,它会减少心理负担/错误来源。 p>

我看到了 3 种处理方法:

  • 在总线上发送了“ID 为 ABC 的命令成功/失败”消息
    流程管理器等待那个消息而不是事件
  • 使 命令执行同步
    如果 process-manager 没有遇到异常,一切正常,继续
  • 介绍一个新活动ApprovalDeclined { WasAlreadyApproved = true }
    此外,流程管理器等待此事件 - 偏角是汇总历史的一部分,也许是优势,也许永远不需要......

我知道:“这取决于”
但是你能想到任何其他(更优雅/更容易/不同)的解决方案吗?您最喜欢的处理此问题的“流程管理器兼容”方式是什么?

【问题讨论】:

    标签: domain-driven-design state event-sourcing aggregateroot saga


    【解决方案1】:

    我认为这没有经验法则。

    消息幂等当然是一件好事,所以简单地忽略消息/状态更改可能是可行的方法。

    我不会再发信号了,因为没有效果。

    【讨论】:

      【解决方案2】:

      我会说这取决于您的域。如果您想警告用户他们正在批准已批准的事物,则必须有一些来自聚合的反馈。它可以是异常as in Deactivate() here,也可以是由应用程序服务/命令处理程序中继的返回值(注意这可能不是 100% 符合 CQRS)。

      如果已经批准的事实对域任务并不重要,您可以忽略该操作或再次执行它。

      从 UI 的角度来看,您很可能无论如何都不允许重新批准某些内容,因此发生这种情况的情况将是微不足道的:2 个用户同时批准、执行“蛮力”批准的脚本等。

      【讨论】:

      • 是的,为depends on your domain +1(或者,常识)。
      【解决方案3】:

      在我看来,您混淆了应用程序和基础架构级别的问题。

      应用程序级别与预期的特定领域行为有关。两次批准的商业理由是什么?为什么一开始会发生这种情况?也许这只是一个 UI 级别的并发问题,但是,为什么多个用户会同时批准同一件事呢?也许他们还没有解决业务层面的问题。首先了解原因至关重要。解决方案通常不在软件本身。

      基础架构级别关注诸如保证消息传递(例如至少一次或恰好一次)之类的事情。当基础设施无法兑现承诺时,这将如何影响业务(如果有)?它如何影响您的流程?无论如何,您的流程是什么?同样,必须从特定领域的角度来推理这些事情。归根结底,您是在降低风险或降低运营成本。

      在这种特殊情况下,在触发批准命令之前问问自己为什么以及如何让您的流程到达它的位置(流程批准有点奇怪,它通常是由人来完成的)。为什么它没有遵守之前的批准(记住,任何聚合都已经批准了)?您可以引入超时(作为对其(过程)未来自我的消息),但在这种情况下这样做似乎有点奇怪(我几乎不知道如何判断)。

      不要采取错误的方式,但我认为您要么需要更深入地挖掘特定领域的事物,要么分享更多细节。

      【讨论】:

      • 我反复阅读您的答案,但我认为这不是我试图弄清楚的重点 - 但仍然非常感谢! (进化的)问题与消息传递无关 - 它更多的是:流程管理器如何知道它的命令成功 - 一般而言?除了给定的案例——这只是一个(可能是坏的)例子——当我已经得出结论我需要实现一个流程管理器(没有 ESB)时,我仍然试着思考该怎么做......
      • ...这会影响聚合处理此无状态更改 - 异常或无事件发射传递的“规则”。要么:没有聚合状态更改 => 异常 => 总线上带有命令 ID 的 CommandFailed 系统事件。尽管聚合处于正确的所需状态,但“失败”?似乎错了。或者:没有聚合状态更改 => 没有发出事件消息的命令“通过” => 总线上的 CommandSucceeded 系统事件。这对我来说最有意义,尽管现在流程管理器监听系统事件,而不是“正常”事件......我只是在这件事上搜索一些指导。
      猜你喜欢
      • 2020-05-09
      • 2020-11-14
      • 2018-03-12
      • 2014-07-29
      • 2016-06-02
      • 2019-09-21
      • 2021-02-02
      • 1970-01-01
      • 2014-02-06
      相关资源
      最近更新 更多