EventStoreBusPublisher类负责从Azure表存储中的虚拟队列中读取聚合的未发布事件,将事件发布到Azure服务总线上,然后从虚拟队列中删除未发布的事件。
如果系统在将事件发布到Azure服务总线和从虚拟队列中删除事件之间失败,那么当应用程序重新启动时,将第二次发布事件。为了避免重复发布事件引起的问题,Azure服务总线被配置为检测重复消息并忽略它们。
Markus(软件开发人员)发言:在出现故障的情况下,系统必须包含一种机制,用于扫描表存储中的所有分区,寻找包含未发布事件的聚合,然后发布这些事件。这个过程需要一些时间来运行,但是只需要在应用程序重新启动时运行。 计算总数
为了保证其自主性,订单和注册限界上下文在不访问会议管理限界上下文的情况下计算订单总数。会议管理限界上下文负责维护会议座位的价格。
每当业务客户添加新的座位类型或更改座位的价格时,会议管理限界上下文就会引发一个事件。订单和注册限界上下文将处理这些事件,并将信息作为其读模型的一部分保存(详细信息,请参考解决方案中的ConferenceViewModelGenerator类)。
当订单聚合计算订单总数时,它使用读模型提供的数据。详细信息请参考订单聚合和PricingService类中的MarkAsReserved方法。
Jana(软件架构师)发言:当注册者向订单添加座位时,UI还动态显示计算的总数。应用程序使用JavaScript计算这个值。当注册者付款时,系统使用订单总数计算的总数。 对测试的影响 Markus(软件开发人员)发言:
不要让通过的单元测试使您产生错误的安全感。当您实现CQRS模式时,有很多灵活的部分。您需要测试它们是否都能正确地协同工作。 Markus(软件开发人员)发言:
不要忘记为读模型创建单元测试。读模型生成器上的单元测试在V1版本发布之前就发现过一个bug,系统在更新订单时删除了订单项。 时间问题
当业务客户创建新的座位类型时,其中有一个验收测试来验证系统的行为。测试中的关键步骤是创建一个会议,为会议创建一个新的座位类型,然后发布会议。这将引发相应的事件序列:ConferenceCreated,SeatCreated和ConferencePublished。
订单和注册限界上下文处理这些集成事件。测试确定订单和注册限界上下文接收这些事件的顺序与会议管理限界上下文发送这些事件的顺序不同。
Azure服务总线只提供先入先出(FIFO),因此,它可能不会按照事件发送的顺序交付事件。在这个场景中,也有可能出现问题,因为在测试中创建消息并将其交付给Azure服务总线的步骤所花费的时间不同。在测试步骤之间引入人为的延迟为这个问题提供了一个临时的解决方案。
在V2版本中,团队计划解决消息排序的一般问题,或者修改基础设施以确保正确的排序,或者在消息确实出现顺序错误时使系统更加健壮。
关于领域专家在第4章“扩展和增强订单和注册限界上下文”中,您看到了领域专家如何参与设计验收测试,以及他的参与如何帮助澄清领域知识。
您还应该确保领域专家参加错误分类会议。他或她可以帮助阐明系统的预期行为,并且在讨论期间可以发现新的用户场景。例如,对与在会议管理限界上下文中取消发布会议相关的bug进行分类时,领域专家确定了一个需求,以允许业务客户将未发布会议的重定向链接添加到新的会议或备用页面。
总结在我们旅程的这个阶段,我们完成了Contoso会议管理系统的第一个伪生产版本。它现在包含了几个集成的限界上下文、一个更加完善的UI,并在订单和注册限界上下文中使用事件源。