3

聚合根是用来控制状态变化的——当前允许什么,不允许什么。如果允许状态转换,请继续。如果不是,你抛出一个异常,解释为什么不允许它。

但是如果状态改变因为已经处于请求状态而没有发生呢?

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

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

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

有经验法则吗?

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

但是让我们为它添加更多的香料(问题背后的实际问题):

认为:

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

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

我看到了 3 种处理方法:

  • 在总线上发送“带有 id ABC 的命令成功/失败”消息
    进程管理器等待消息而不是事件
  • 如果进程管理器没有遇到异常,则使命令执行同步
    ,一切都很好,继续
  • 另外引入一个新事件ApprovalDeclined { WasAlreadyApproved = true }
    ,流程管理器等待这个事件 - 偏角是总历史的一部分,也许是一个优势,也许永远不需要......

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

4

3 回答 3

2

我认为这不会有经验法则。

消息幂等当然是一件好事,因此简单地忽略消息/状态更改可能是要走的路。

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

于 2014-09-30T08:25:06.363 回答
1

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

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

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

于 2014-09-30T09:42:40.543 回答
0

对我来说,您似乎混淆了应用程序和基础架构级别的问题。

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

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

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

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

于 2014-11-01T14:15:54.807 回答