考虑一下情况:
public class OrderController {
IBus bus;
public OrderController(IBus bus) {
this.bus = bus;
}
public ActionResult Checkout(String orderId) {
var command = new CheckoutOrderCommand(orderId);
bus.Send(command);
return Redirect("on-success-url");
}
}
相应的命令处理程序(在单独的程序集中定义)正在等待处理的incomming消息。
但是我们已经说过发送一切都好
return Redirect("on-success-url");
如果处理程序无法保存对域的更改,该怎么办?
嗯,可以在命令处理程序端使用队列来发布响应,以便将Web应用程序订阅到队列。
最终用户如何获得即时/同步ui响应,这将反映对域的真正更改?我应该这样做吗?
通过消息总线处理命令是否仅适用于没有确认的后台任务?
答案 0 :(得分:8)
这取自您可能感兴趣的«Busting some CQRS myths», Jimmy Bogard blog:
神话#4 - 命令是“一劳永逸”
您的工作中有多少业务流程真正发生火灾?您通常至少需要一个同步确认来接收和接受该命令。如果您正在执行该命令的异步发送,您如何通知用户?电子邮件?他们还好吗?
相反,对于需要繁重工作以完成请求的命令,我们确实有两件事情在继续:
- 接受请求
- 完成请求
接受请求应该是同步的。实现不必是。但是对于异步实现的模型,我们仍然可能需要关联请求等的方法,而这正是您经常看到工作流/流程/ sagas发挥作用的地方。
我总是试图让我的命令同步。如果处理时间很长,我会使用像流程管理器或传奇这样的东西。
答案 1 :(得分:4)
如果您确实想要发送请求并等待响应,可以使用IRequestClient
接口,并将MessageRequestClient
的实例添加到容器中 - 并使用该依赖项而不是使用IBus
直接。这将使您可以等待请求的响应,并返回API上的内容。
当然,您已将控制器与服务的可用性相结合 - 这并不总是一件坏事 - 但需要注意的事项。
使用请求客户端的示例代码可以在文档中找到,该文档与您描述的完全相同。
http://docs.masstransit-project.com/en/mt3/usage/request_response.html
答案 2 :(得分:2)
这在某种程度上取决于您的命令总线实现。某些系统允许命令处理程序将回复发送回原始发件人。
您的情况下的标准解决方案是不承认实际的结帐,而只是确认命令的收据,现在正在处理结账。对于结账,这通常是完全正常的,因为无论如何订单需要花费几个小时来处理。
如果您确实需要显示一些即时结果,则可以在给定时间范围内没有预期结果的情况下轮询另一项服务以获得完成状态和/或超时。
如果这对您来说过于复杂,请不要使用异步命令总线,而应使用同步命令处理,其中故障会立即传播到客户端。