我对使用域事件构建读取模型的系统中的流程感到有些困惑。特别是,我们如何处理用户期望数据(及其视图)在完成命令时发生更改的事实,但由于我们的系统架构(对发布事件的非阻塞调用),实际数据库可能不会在页面重新加载?
我希望使用事件和服务总线将我们的一个系统的设计与CQRS更加一致。
让我说我的流程如下:
用户点击查看中的按钮,执行从其帐户中删除付款方式的任务。
控制器调用PaymentMethodRemovalService,并将其传递给accountId& paymentMethodId。
Controller使用AccountRepository检索帐户并调用account.RemovePaymentMethod(id)
帐户验证可以进行操作并发布事件PaymentMethodRemovedMessage(accountId,paymentMethodId)
由于事件发布是异步的,我们现在必须从服务返回并从控制器返回视图 - 但我们的实际数据尚未更新!
处理程序,IHandle< PaymentMethodRemovedMessage>,听到事件并从数据库中删除实际行
那么,一个人要做什么?
我可以简单地说,删除显示付款方式的div。这可能适用于AJAX场景,但如果我使用Post-Redirect-Get来支持非JavaScript客户端会怎样。然后我将触发我的Get并从查询方面读取数据,可能在它更新之前。
我是否只是显示一条通知,说明他们已提交删除付款方式的请求? (这似乎不友好,提交订单是有意义的,但不是,例如,更改地址)。
有没有办法将实施更改作为解耦的异步事件进行协调,并显示反映其当前更改的用户数据?
编辑:我的问题非常类似于CQRS, DDD synching reporting database我必须说,在那里给出的答案,也在这里提到,有一点气味 - 争论用户界面以显示更新的内容带有读DB的带,可以这么说。我希望有点清洁。
答案 0 :(得分:8)
如果您被锁定在请求/响应模型中,则可以采用相关请求/响应模式。有关详细信息,请查看NSB下载中的Async Pages示例。这演示了ASP.NET设置中的请求/响应。如果你更喜欢那里有一些ASP.NET MVC例子。
当您引入异步处理时,您接受数据将是陈旧的。有人可能会争辩说,在您查询数据库时,数据已经过时(网络延迟,渲染时间等)。既然数据已经老了,我们必须问多大年纪已经足够了?
还需要考虑的另一件事是你的处理有点乱。步骤3应该在将命令发送到服务器之前验证该命令,然后步骤3,4将在6之后进行。只有在命令有效且仅在数据库成功更新时才应发布事件时才应更新数据库。
答案 1 :(得分:0)
此问题称为“最终一致性”。有明确的方法来处理它。要做的第一点是,无论是否使用异步事件,每个系统都具有最终的一致性。只是你选择让它显式化,而大多数其他系统只是让用户等到更新完成。只要明确选择这两种方法,这两种方法都是有效的。
前段时间我写了一篇关于这个主题的博客文章,你可能会觉得有帮助。您可以在此处找到它:4 Ways to Handle Eventual Consistency on the UI
这是一个简短的版本:
选项1 - 使用确认屏幕。如果您在手机上使用银行应用程序,您可能已经看到了这一点。转移一些钱,在流程结束时,您将被带到确认屏幕,然后再返回到您的帐户。这使系统有时间回到最新状态。
选项2 - 伪造它。如果用户尝试的操作极有可能成功,那么伪造它可能是合法的方法。这通常在购买需求量很大的门票时使用。您的交易可能会通过,但后来该公司发现您的机票已经在几毫秒之前售出。对公司的好处是他们有销售而不是冒失去两个客户的风险。只要系统建立得很仔细,这种情况就很少发生,因此整体上都不是问题。
您还可以使用相关ID来订阅操作的成功或失败。
无论如何,希望能提供一些思考的食物。