使用 CQRS 和 CQRS 时显示视图中的更改具有领域事件和领域事件的 DDD服务总线
我对使用域事件构建读取模型的系统中的流程有点困惑。特别是,我们如何处理这样一个事实:用户期望数据(及其视图)在完成命令时发生更改,但由于我们的系统架构(对发布事件的非阻塞调用),实际数据库可能不会在执行命令之前发生更改。页面已重新加载?
我希望使用事件和服务总线使我们的系统之一的设计更加符合 CQRS。
假设我的流程如下:
用户单击视图中的按钮以执行从其帐户中删除付款方式的任务。
控制器调用 PaymentMethodRemovalService,将其传递给 accountId & paymentMethodId。
控制器使用 AccountRepository 检索 Account 并调用 account.RemovePaymentMethod(id)
Account 验证操作是否可以发生并发布事件 PaymentMethodRemovedMessage(accountId) , paymentMethodId)
由于事件发布是异步的,我们现在必须从服务返回并从控制器返回视图 - 但是我们的实际数据尚未更新!
一个处理程序,IHandle< PaymentMethodRemovedMessage >,侦听事件并从数据库中删除实际行
那么,一个人该怎么做呢?
我可以简单地删除显示付款方式的 div。这可能适用于 AJAX 场景,但如果我使用 Post-Redirect-Get 来支持非 JavaScript 客户端,该怎么办?然后,我将触发 Get 并从查询端读取数据(可能在更新之前)。
我是否只显示一条通知,说明他们删除付款方式的请求已提交? (这似乎不友好,对于提交订单有意义,但对于更改地址而言则不然)。
有没有办法协调将更改实现为解耦的异步事件并显示反映当前更改的用户数据?
编辑:我的问题与 CQRS,DDD 同步报告数据库 我不得不说,那里给出的答案以及这里也提到的答案,有一点味道 -可以说,调整用户界面以显示与读取的数据库无关的更新。我希望有一些更干净的东西。
I'm a little confused about the flow in a system using domain events to build the read model. Particularly, how do we deal with the fact that the user expects data (and its view) to change when they complete a command, but due to our system architecture (non-blocking calls to publish events) the actual database might not change before the page is reloaded?
I'm hoping to move the design of one of our systems more inline with CQRS using events and a service bus.
Let's say my flow goes as such:
User clicks button in View to perform Task of removing Payment Method from their Account.
Controller calls PaymentMethodRemovalService, passing it accountId & paymentMethodId.
Controller uses AccountRepository to retrieve Account and calls account.RemovePaymentMethod(id)
Account validates that operation can occur and publishes event PaymentMethodRemovedMessage(accountId, paymentMethodId)
Because event publishing is asynchronous, we now have to return from service and return view from the controller - but our actual data isn't updated yet!
A handler, IHandle< PaymentMethodRemovedMessage >, hears the event and removes the actual row from the DB
So, what's a guy to do?
I could simply, say, remove the div that was displaying the payment method. This may work in an AJAX scenario, but what if I'm using Post-Redirect-Get to support non-JavaScript clients. Then I will be firing my Get and reading the data from the Query side of things, potentially before it's updated.
Do I just show a notification saying their request to remove the payment method has been submitted? (which doesn't seem to friendly, makes sense for submitting an order, but not for, say, changing an address).
Is there a way to reconcile implementing changes as decoupled asynchronous events and showing the user data that reflects their current change?
EDIT: My question is quite similar to CQRS, DDD synching reporting database I have to say, the answer given there and also alluded to here, has a bit of a smell to it - wrangling the UI to show an update that's out of band with the read DB, so to speak. I was hoping for something a little cleaner.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果您被锁定在请求/响应模型中,您可以采用相关请求/响应模式。有关详细信息,请查看 NSB 下载中的异步页面示例。这演示了 ASP.NET 设置中的请求/响应。如果您更喜欢的话,这里有一些 ASP.NET MVC 示例。
当您引入异步处理时,您就接受了数据将过时的事实。有人可能会说,当您查询数据库时,数据已经很旧了(网络延迟、渲染时间等)。由于数据已经很旧了,我们必须问多旧的数据才足够好?
另一件需要考虑的事情是您的处理有点无序。步骤 3 应在将命令发送到服务器之前验证命令,然后步骤 3、4 将在步骤 6 之后进行。仅当命令有效时才应更新数据库,并且仅当数据库成功更新时才应发布事件。
If you are locked into the Request/Response model you could adopt a Correlated Request/Response pattern. For specifics, check out the Async Pages sample in the NSB download. This demonstrates Request/Response in an ASP.NET setting. There are some ASP.NET MVC examples out there if that is more your thing.
When you introduce asynchronous processing you are accepting that the data will be stale. One can argue that the moment you query the DB the data is already old(network latency, rendering time etc.). Since the data is already old, we must ask how old is good enough?
One more thing to consider is that your processing is a bit out of order. Step 3 should be validating the command prior to sending it to the server and then steps 3, 4 would come after 6. The database should only be updated if the command is valid and the event should only be published if the database is successfully updated.
这个问题被称为“最终一致性”。有明确的方法可以实现这一目标。首先要指出的是,每个系统都具有最终一致性,无论它们是否使用异步事件。只是您选择将其明确显示,而大多数其他系统只是让用户等待更新完成。只要明确选择,这两种方法都是有效的。
不久前,我写了一篇关于这个主题的博客文章,您可能会发现它有帮助。您可以在这里找到它:处理最终事件的 4 种方法UI 的一致性
这是一个简短的版本:
选项 1 - 使用确认屏幕。如果您在手机上使用银行应用程序,您可能已经看到过这种情况。转账一些钱,在该过程结束时,您将进入确认屏幕,然后返回您的帐户。这使系统有时间恢复到最新状态。
选项2-假装它。如果用户尝试的操作很可能成功,那么伪造它可能是一种合法的方法。当购买需求量很大的门票时,通常会使用此方法。您的交易可能会成功,但后来公司发现您的门票在几毫秒前就已经售出。对公司来说,好处是他们能获得销售,而不是冒着失去两个客户的风险。只要系统构建得仔细,这种情况就应该很少发生,因此总体上不会成为问题。
您还可以使用相关 ID 来订阅操作的成功或失败。
无论如何,希望能提供一些值得深思的东西。
This problem is referred to as 'Eventual Consistency'. There are clear ways to approach it. The first point to make is that every system has eventual consistency whether they are using async events or not. It's just that you have opted to make it explicit while most other systems just make the user wait until the update is complete. Both approaches are valid as long as they are explicitly chosen.
A while back I wrote a blog post on this subject which you may find helpful. You can find it here: 4 Ways to Handle Eventual Consistency on the UI
Here is a short version:
Option 1 - Use a confirmation screen. If you use a banking app on your phone you've probably seen this in action. Transfer some money and at the end of the process, you are taken to a confirmation screen before being taken back to your accounts. This gives the system time to get back up to date.
Option 2 - Fake it. If the operation the user is attempting is highly likely to succeed, then faking it can be a legitimate approach. This is often used when purchasing tickets which are in high demand. Your transaction may go through, but later the company discovers your ticket had already been sold milliseconds before. The benefit to the company is that they have the sale rather than risking losing both customers. So long as the system is built carefully this situation should rarely occur and therefore not be a problem overall.
You can also use correlation id's to allow you to subscribe to success or failure of operations.
Anyway, hope that provides some food for thought.