【问题标题】:How to connect command with resulting events如何将命令与结果事件连接起来
【发布时间】:2022-02-23 05:47:41
【问题描述】:

我尝试将我们广泛的遗留系统模块化。我认为使用命令/查询/事件作为每个模块的公共 API 并专注于通信。我想以异步方式对整个通信进行建模。但是为了有效地使用命令/事件,我需要知道某个特定事件已作为特定命令的效果而引发。例如,我想向 Warehouse 模块发送一个命令 Book(SKU, quantity)。然后我对那个具体命令的结果感兴趣,而不是关于在仓库中预订物品的任何情况。某些方面可能会同时发送相同的(语义上)命令,但我(作为客户端模块)只对我的命令的结果感兴趣。我知道我可能会将相关 ID 附加到我的事件中,但 AFAIK 更多的是关于跟踪/调试,而不是关于应用程序设计本身。这里有什么替代方案?

这个问题也与 sagas 有关。假设有 Set 聚合。它允许您在里面添加数字。 Set 允许多次接受相同的数字。 Saga 发出命令 Add(setId, number) 并等待事件 added(setId, number)。我们如何知道该事件是否因我们的命令而发生?与此同时,其他人可能会发出相同的命令。但我们想确定这是我们的命令导致的事件。将特定数字添加到集合中并不重要。重要的是我们的号码已被添加(即使重复)。也许我的想法有心理缺陷。也许系统应该关心真正的后果?但是很难想象我会如何解决上述问题。

【问题讨论】:

  • 您的活动类似于MyCommandCompletedEvent。它绝对应该包含原始命令的 id,这就是您的客户端将事件与命令相关联的方式。

标签: architecture event-handling cqrs event-driven


【解决方案1】:

如果域关心哪个命令引发了事件(无论是否在 saga 中),那么包含足以识别命令的内容并没有错(可以是请求者提供的唯一 ID,也可以是整个事件中带有一些元数据的命令。

也就是说,对于具有以下解释的命令有一些话要说:“使系统的状态符合此请求”。在这些情况下,您不必关心特定命令是否更改了状态,因为关心这一点(尤其是在引入重试时)需要您记录一个虚拟事件,当您有命令时该事件实际上不会改变状态(例如重试,但它也可能正常发生,因为请求者可能正在使用陈旧的视图)。

如果您关心某个特定命令是否被接受,总体而言,为这些命令提供请求/响应语义并以成功消息进行响应可能是更好的方法。

  • 进程1发送Add(set123, 4)
  • Added(set123, 4) 被持久化
  • 进程 1 未收到成功响应
  • 进程 2(或者可能重试进程 1,这并不重要)发送 Add(set123, 4)
  • 因为 4 已经在 set123 中,所以发送成功响应

【讨论】:

  • 我听说过保持对每个命令状态的读取/查询/日志,甚至发布某种应用程序事件 CommandSucceed(commandId) 的想法。这可能不是你在这里的意思。我希望保持这种通信异步,并且我不希望通过区分命令类型来干扰我的域。我如何在这里处理该请求/回复异步模式?我假设我的请求仍然是命令,但回复不再是事件。但是这些部分是如何连接的呢?
  • 发布CommandSucceeded(commandId) 事件是完全可以接受的。如果您要求知道哪个命令成功了,并且您没有做出超出“领域事件流”围绕领域层如何与其他层交互的假设,那么这意味着某些区分命令的方法(不一定它们的类型)您的域的固有部分,并且发布成功的命令是您可以做到的唯一方法。
  • 记住巴生猜想可能会有所帮助:如果您无法仅使用人、笔和纸来解决这个问题,那么您就无法合理地期望如何使用软件来解决它/计算机。
  • 我认为命令处理程序是应用层的一部分,而不是域层。就从聚合中引发的所有域事件而言,从命令处理程序发布其他应用程序事件是可行的。甚至可能有一些专用总线用于此类消息(命令成功,命令失败)。这样的推理合理吗?为了处理重试,我可能必须保留命令日志,是吗?我可以在哪里阅读更多关于所有这些内容的信息?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-06
  • 2019-03-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多