考虑一个Web应用程序,该Web应用程序除了将查询(即添加,更新,删除)以外的所有数据库操作均作为NServiceBus消息进行了实施,因此,每当用户调用Web API时,它将在后端将其映射到{{1 }}方法,以在同一HTTP请求连接中返回响应。
挑战是消息处理程序需要发送其他一些消息并等待其响应完成其工作时。 NServiceBus不允许在消息处理程序内调用await endpointInstance.Request
。
我最终使用Saga来实现依赖于某些其他消息处理程序响应的消息处理程序。但是Saga的问题在于我无法在同一HTTP请求中发回结果,因为Saga使用发布/订阅模式。
我们所有的Web API都需要在同一HTTP请求中响应(连接应保持打开状态,直到收到结果或发生超时异常为止)。 是否有任何清洁的解决方案(最好不使用Saga)?
示例场景:
Request
await endpointInstance.Request<PurchaseResult>(new PurchaseMessage(itemId, paymentId));
处理程序应调用PurchaseMessage
await endpointInstance.Request<AddPaymentResult>(new AddPaymentMessage(paymentId));
成功,则将购买详细信息存储在数据库中,并以AddPaymentResult
的形式返回true
,否则返回PurchaseResult
答案 0 :(得分:4)
您正在尝试实现我们(在特定软件中)试图积极预防的某些事情。让我解释一下。
使用远程过程调用(RPC),可以在进程外调用另一个组件。这就是使过程称为“远程”的原因。在常规编程中,您可以在过程中完成所有事情,而且速度很快,而使用RPC则需要序列化,延迟等更多的开销。基本上,您必须处理the fallacies of distributed computing。
仍然,人们出于各种原因这样做。有时是因为您想使用WebAPI(或“老式” Web服务),因为它提供了您不想开发的功能。这本书中最古老的示例是通过邮政编码搜索地址。或从某人的银行帐户中扣除款项。如果要构建CRM,则可以使用这些远程组件。如今,许多人建造了分散的整体,因为他们在会议上被告知这是一件好事。在架构图中,它看起来确实不错,但是仍然存在时间耦合,这可能会带来很多麻烦。
其中一些令人头疼的事实是您试图以原子动作来做某事。过去,通过过程中的代码/类/等的调用,此操作既简单又快速。直到遇到限制,例如数据库上的大量锁。
对此的一种解决方案是异步通信。您通过“发射后遗忘”发送一些信息。这解决了时间耦合。因此,您的网站正在停滞不前,而不是拥有一个数据库,该数据库无法收到数十个请求来更新数据等,因此,您的网站正在停滞不前。这确实是一件好事,因为您可以使用各种较小的操作,而不是单个原子操作,并且可以使用多种方法来分配工作,扩展系统等。
这还带来了其他挑战,因为并非每个人都能一劳永逸。一些已经构建的系统尝试通过消息传递(以及希望的NServiceBus)引入异步通信。有些零件可以完美地工作。但是其他部分不能。主要是用户界面(UI)。因为它的构建是为了立即获得结果。因此,当您从用户界面发送消息时,您会期望得到结果!
借助NServiceBus,我们构建了一个名为“客户端回调”的程序包,以使之成为可能。强烈建议我们的客户不要使用它,除了我刚才描述的这种特定情况。最好迁移整个UI来处理您无法立即得到答复的事实,但是我们知道这是一项艰巨的工作,因此实现这一目标的人并不多。
但是,一旦发送了第一条消息并且UI收到了结果,就不再需要使用回调。因此,我想提出以下方案:
await endpointInstance.Request<PurchaseResult>();
PurchaseMessage
处理程序检索所需的信息,然后将消息发送或发布到其他组件,然后将其答案答复给Web服务器。让我们知道是否需要更多信息。您可以随时通过发送电子邮件至support@particular.net与我们联系