Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/.htaccess/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Domain driven design CQRS-何时发送确认消息?_Domain Driven Design_Cqrs - Fatal编程技术网

Domain driven design CQRS-何时发送确认消息?

Domain driven design CQRS-何时发送确认消息?,domain-driven-design,cqrs,Domain Driven Design,Cqrs,示例:业务规则规定客户在下单时应收到确认消息(电子邮件或类似消息) 假设一个newordereregisteredevent从域中发送,并由发送确认消息的事件侦听器拾取。完成此操作后,其他一些事件处理程序会抛出异常或出现其他错误,并回滚工作单元。我们现在已经向用户发送了一条已回滚的内容的确认消息 在完成一个工作单元后,如果您想做一些事情,那么解决此类问题的“cqrs”方法是什么?另一个复杂因素是事件的重播。我不希望每当我重播录制的事件以构建新的视图/投影时,都会重新发送旧的确认消息 到目前为止,

示例:业务规则规定客户在下单时应收到确认消息(电子邮件或类似消息)

假设一个
newordereregisteredevent
从域中发送,并由发送确认消息的事件侦听器拾取。完成此操作后,其他一些事件处理程序会抛出异常或出现其他错误,并回滚工作单元。我们现在已经向用户发送了一条已回滚的内容的确认消息

在完成一个工作单元后,如果您想做一些事情,那么解决此类问题的“cqrs”方法是什么?另一个复杂因素是事件的重播。我不希望每当我重播录制的事件以构建新的视图/投影时,都会重新发送旧的确认消息


到目前为止,我最好的理论是:我刚刚开始研究CQR的迷人世界,想知道这是否会成为一个传奇?如果一个传奇就像一个状态机,每个转换只能发生一次,那么我想这会解决这个问题吗?我只是很难想象这将如何与命令总线和域事件相结合

有两种可能的解决方案

1) 发布事件和处理事件(即电子邮件)是单个事务的一部分。在这种情况下,您的事务框架会为您处理它。如果电子邮件失败,则事件将回滚。您可能会重试该命令。这在概念上是清晰的,易于思考。在每个有发言权的人都有发言权之前,任何事件都不会完成发布。然而实际上,这可能是痛苦的,因为它通常涉及分布式事务。这些很难得到。您的电子邮件客户端是否可以注册与保存您的事件的数据库相同的事务

2) 事件的发布是事务性的,但每个事件处理程序都以自己的方式处理事务。发送电子邮件的事件处理程序可以跟踪它看到的事件。如果它崩溃,它将请求旧事件并处理它们。你可以做一个商业决定,如果人们有丢失或重复的电子邮件,这会有多重要。(对于与金钱有关的交易,答案可能是你不应该允许。)

解决方案(2)通常是您在DDD/CQRS圈中看到的提升,因为它是更松散耦合的解决方案。解决方案(1)在一个小型系统中非常实用,其中事件存储和投影位于单个数据库中,并且投影不会经常更改。解决方案(2)允许多种事件处理程序以各自的方式工作。解决方案(1)可能导致许多非重叠关注点被纠缠。在这种情况下,您的订单业务规则只有在电子邮件中发生的许多奇怪的事情得到处理后才能完成。首先,它可能会让你慢下来不少

如果发送电子邮件比“看到了事件,发送了电子邮件”更有趣,那么你是对的,你可能手头有一个传奇或工作流程。在大型运营中,电子邮件本身往往是一个复杂的系统,您不太可能需要实现很多功能。您只需确保将电子邮件放入某种请求队列(使用方法(2)),电子邮件系统可能会重试/批处理/避免垃圾邮件/通宵工作等

  • 事件只应在事务完成后发生。如果出现任何错误,并且出现了回滚,那么从外部角度来看,事件并没有发生。因此,它根本不应该出版。尽管必要时可以发布
    OrderRegistrationFailed
    事件

  • 除非命令已成功执行,否则您不希望发送邮件

    第一个原因是命令处理程序——正如另一个答案中所建议的那样——位于错误的位置:在某些情况下,命令处理程序无法判断命令是否最终会成功。让命令处理程序调用邮件发送也会将流程知识放入命令处理程序中,这会破坏SRM,并使业务规则与应用程序层紧密耦合

    邮件应在事件发生后发送,即从事件处理程序发送

    为了防止该处理程序在重播期间触发,您可以不注册它。这与测试应用程序的方式类似。您只注册实际需要的处理程序

    • 生产系统->注册所有事件处理程序
    • 测试->仅注册已测试的事件处理程序
    • Replay->仅注册投影/非规范化处理程序

  • 另一种——更松散的耦合,尽管有点复杂——可能是有一个
    Saga
    处理
    newordereregisteredevent
    ,并向适当的有界上下文发出
    SendMail
    命令(感谢Yves Reynhout在问题的评论中指出这一点)。

    发出“发送电子邮件”发送一条消息。如果uow回滚,则消息的调度(到持久存储器)也会回滚。其他人会收到信息,并发送电子邮件。顺便说一句,与cqrs无关。普通的分布式计算常识。至于事件重播,这永远不会导致这种行为。如果你的建议。是的,你做错了。这是有道理的,但我对cqrs的背景感兴趣。什么是“信息”?谁/什么人会在何时接电话?最好利用事件存储来避免引入另一种存储机制来跟踪传出的通信。您的事件存储就是您的队列。然而,实际发送电子邮件的代码需要通过基于拉或推的机制/技术进行通知。@YvesReynhout:这实际上刚刚开始