来自CRUD风格的限界上下文的集成事件可能包含状态数据,因此只需要最后一个事件。例如,如果来自会议管理限界上下文的事件包含当前座位配额,您可能对以前的值不感兴趣。
另一种要考虑的方法是使用多个限界上下文共享的事件存储。这样,原始的限界上下文(例如CRUD风格的会议管理限界上下文)可以负责持久化集成事件。
greg Young -与模式和实践团队的对话。
关于Azure服务总线的一些说明前面的讨论提出了一种在会议管理限界上下文中避免使用分布式两段提交的方法。然而,也有其他的方法。
虽然Azure服务总线不支持分布式事务(把总线上的一个操作和数据库上的一个操作合并),但您可以在发送消息时使用RequiresDuplicateDetection属性,和在收到消息使用PeekLock模式。这样可以创建出所需级别的健壮性而不使用分布式事务。
作为替代方案,您可以使用分布式事务来更新数据库,并使用本地Microsoft消息队列(MSMQ)发送消息。然后可以使用桥接器将MSMQ队列连接到Azure服务总线队列。
有关实现从MSMQ到Azure服务总线的桥接的示例,请参阅Microsoft Azure AppFabric SDK中的示例。
有关Azure服务总线的更多信息,请参见参考指南中的第7章“在参考实现中使用的技术”。
推送更改到会议管理限界上下文将关于已完成订单和注册的信息从订单和注册限界上下文中推送到会议管理限界上下文中引发了一系列不同的问题。
订单和注册限界上下文通常在创建订单时引发以下许多事件:OrderPlaced,OrderRegistrantAssigned,OrderTotalsCalculated,OrderPaymentConfirmed,SeatAssignmentsCreated,SeatAssignmentUpdated,SeatAssigned和 SeatUnassigned。限界上下文使用这些事件在聚合和事件源之间进行通信。
对于会议管理限界上下文来说,要捕获显示注册和参会者详细信息所需的信息,它必须处理所有这些事件。它可以使用这些事件包含的信息来创建数据的非规范化SQL表,然后业务客户可以在UI中查看这些数据。
这种方法的问题是会议管理限界上下文需要从另一个限界上下文理解一组复杂的事件。这是一个脆弱的解决方案,因为订单和注册限界上下文的更改可能会破坏会议管理限界上下文中的这一特性。
Contoso计划为系统的V1版本保留这个解决方案,但是将在旅程的下一阶段评估其他方案。这些替代方案将包括:
修改订单和注册限界上下文,以生成为集成而显式设计的更有用的事件。
在订单和注册限界上下文中生成非规范化数据,并在数据准备好时通知会议管理限界上下文。然后,会议管理有界上下文可以通过服务调用请求信息。
备注:要查看当前方法如何工作,请查看源代码中Conference项目里的OrderEventHandler类。
选择何时更新读端数据在会议管理有界上下文中,业务客户可以更改座位类型的描述。这将引发一个SeatUpdated事件,由ConferenceViewModelGenerator类在订单和注册限界上下文中处理。该类更新读模型数据,以反映有关座椅类型的新信息。当注册者下订单时,UI显示新的座位描述。
然而,如果注册者查看先前创建的订单(例如为参会者分配座位),注册者将看到原始的座位描述。
Carlos(领域专家)发言:这是一个要反复思考的商业决策。我们不想让注册者因为在创建订单后更改座位描述而混淆。 Gary(CQRS专家)发言:
如果我们想要更新现有订单上的座位描述,我们需要修改PricedOrderViewModelGenerator类来处理SeatUpdated事件并调整它的视图模型。 分布式事务和事件源
上一节讨论了会议管理限界上下文的集成选项,提出了使用分布式两段提交事务的问题,以确保存储会议管理数据的数据库和向其他限界上下文发布更改的消息传递基础设施之间的一致性。
实现事件源时也会出现同样的问题:必须确保存储所有事件的限界上下文中的事件存储与将这些事件发布到其他限界上下文中的消息传递基础设施之间的一致性。
事件存储实现的一个关键特性应该是,它提供了一种方法来确保其存储的事件与限界上下文发布到其他限界上下文的事件之间的一致性。
Carlos(领域专家)发言:如果您决定自己实现一个事件存储,这是您应该解决的一个关键挑战。如果您正在设计一个可伸缩的事件存储,并计划将其部署到分布式环境(如Azure)中,那么您必须非常小心,以确保满足这一需求。 自治和授权
订单和注册限界上下文负责代表注册者创建和管理订单。支付限界上下文负责管理与外部支付系统的交互,以便注册者可以为他们订购的座位付费。