聚合根:状态更改或失败,异常或......?

时间:2014-09-30 07:33:00

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

聚合根用于控制状态变化 - 当前允许的内容和不允许的内容。如果允许状态转换,请继续。如果没有,你会抛出一个异常,解释为什么不允许它。

但是,如果 state- 更改没有发生,那是因为 已经处于请求状态

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

  • 是否应抛出例外 a la“ XYZ已获批准”?
  • 或者应该默默忽略
  • 或者状态变化是否应该“再次发出信号”(事件采购,下一段)?

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

有经验法则吗?

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

但是让我们再添加一些 spice (问题背后的实际问题):

假设:

  • 消息总线
  • async 命令/事件处理
  • 流程经理

如果进程管理器(也称为saga)发出命令(异步)并想知道命令是否成功,该怎么办?我认为如果流程管理员不必关心关于此实现细节,它将减少心理负载/错误源

我看到有三种处理方法:

  • 在公交车上发送“具有ID ABC成功/失败的消息”消息 process-manager等待那条消息而不是事件
  • 使命令执行同步
    如果流程经理没有遇到异常,一切都很好,继续前进
  • 介绍新活动ApprovalDeclined { WasAlreadyApproved = true }
    此外,流程管理者等待此事件 - 赤字是总体历史的一部分,可能是一个优势,也许永远不需要......

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

3 个答案:

答案 0 :(得分:2)

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

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

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

答案 1 :(得分:1)

我会说这取决于你的域名。如果您想警告用户他们正在批准已经批准的东西,则必须从汇总中获得一些反馈。它可以是异常as in Deactivate() here,也可以是应用程序服务/命令处理程序中继的返回值(请注意,这可能不符合100%CQRS)。

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

从用户界面的角度来看,您很可能不会允许重新批准某些内容,因此发生这种情况的情况将是微不足道的:2个用户的并发批准,执行“强力”批准的脚本等。

答案 2 :(得分:0)

对我而言,似乎让您对应用程序和基础架构级别的问题感到困惑。

应用程序级别与预期的域特定行为有关。批准两次的商业理由是什么?为什么甚至会发生这种情况?也许它只是一个UI级别的并发性事物,但是,为什么多个用户在同一时间批准相同的事情呢?也许在业务层面存在一个尚未解决的问题。理解为什么首先是必不可少的。解决方案通常不在软件本身中。

基础设施级别涉及诸如保证消息传递之类的事情(例如,至少一次或恰好一次)。当基础设施无法兑现承诺时,这对业务有何影响(如果有的话)?它如何影响您的流程?无论如何,你的过程是什么?同样,从域特定的角度来理解这些事情是至关重要的。在一天结束时,您可以进行风险或运营成本缓解。

在这种特殊情况下,问问自己为什么以及如何在启动批准命令之前将进程放在原处(对于批准过程有点奇怪,它通常由人类完成)。为什么它没有观察到之前的批准(请记住,什么是聚合已经批准)?你可以引入一个超时(作为一个消息给它(过程)未来的自我)但在这种情况下这样做似乎有点奇怪(我不知道差不多可以告诉你)。

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