【问题标题】:Am I over-complicating this? (CQRS, Domain Events, and Command Failures)我是否过于复杂了? (CQRS、领域事件和命令失败)
【发布时间】:2019-01-13 18:54:15
【问题描述】:

我正在开发一个包含域事件的 CQRS 框架,我遇到了一种代码异味,我希望得到一些建议。

我没有使用事件溯源 (ES)。 ES 事件与领域事件不同。域事件是域感兴趣的并且可能导致发出新命令。 ES 事件对持久存储很感兴趣。一个 ES 事件也可能是一个领域事件,但并不是所有的 ES 事件都是领域事件。

我的问题的根源在于语句:

域事件……可能会导致新命令……

具体来说,当这些命令之一失败时会发生什么。

在我读过的 CQRS 文章中,他们说应用层负责在命令发送到命令总线之前对其进行验证。 我不同意这一点有两个原因。 1)我不信任客户端(安全欺骗)。 2) 随着应用程序的成熟和新事件/处理程序/命令的添加,命令 A 的验证可能不知道它还需要验证命令 Foo。

因此,应用层需要知道命令是否成功。如果失败,应用层需要一些信息来解释原因。但是使用触发事件的命令会发出触发事件的新命令……我最终得到的响应类如下所示:

public interface ICommandResponse
{
    ICommand OriginatingCommand { get; set; }
    bool Successful { get; set; }
    IEnumerable<Exception> Exceptions { get; set; }
    IEnumerable<ICommandResponse> DerivativeCommands { get; set; }
    IEnumerable<IEventResponse> EventResponses { get; set; }
}

public interface IEventResponse
{
    IEvent OriginatingEvent { get; set; }
    bool Successful { get; set; }
    IEnumerable<Exception> Exceptions { get; set; }
    IEnumerable<IEventHandlerResponse> EventHandlerResponses { get; set; }
}

public interface IEventHandlerResponse
{
    string Descriptor { get; set; } // TODO: A way to identify the event handler.
    bool Successful { get; set; }
    IEnumerable<Exception> Exceptions { get; set; }
    IEnumerable<ICommandResponse> DerivativeCommands { get; set; }
}

我想要的只是能够判断一个命令是成功还是失败,如果失败了,为什么。我最终得到了这个递归树结构。我是否过于复杂了?

【问题讨论】:

  • 是的;看起来过于复杂。并非一切都必须如此通用。不过,我不确定该向您推荐什么。

标签: c# cqrs domain-events


【解决方案1】:

当其中一个命令失败时会发生什么

因此,在域事件的通常上下文中,答案是整个事务都失败了。

我只想知道一个命令是成功还是失败,如果失败了,为什么。

这些信息如何返回给调用者取决于您的代码风格——您可以抛出异常,或返回某种Either 数据类型,或通知回调处理程序,或者...

如果调用者在另一个进程中,您将需要将内部选项转换为某种消息。带有可选原因字段的成功/失败状态将使您有足够的经验来确定您希望在下一个版本的架构中包含什么。

【讨论】:

  • 这意味着域事件处理程序需要在与触发该域事件的更改相同的事务中执行。这是正确的吗?如果您使用没有事务的文档数据库,您如何做到这一点?
猜你喜欢
  • 2015-11-19
  • 2019-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-16
  • 1970-01-01
  • 1970-01-01
  • 2020-07-12
相关资源
最近更新 更多