【问题标题】:Handling Race condition in CQRS/ES with read-side使用读取端处理 CQRS/ES 中的竞态条件
【发布时间】:2020-11-18 13:40:23
【问题描述】:

我正在构建一个用于管理健康诊所的应用程序。

我们在安排约会时发现了一个竞争条件案例,直到现在,团队成员都没有找到解决方案。

安排约会时,需要验证一些业务规则:

  • 不能与同一医生或同一患者安排在同一时间
  • 医生一个月只能参加N次预约
  • 一周内,医生只能参加N次预约

因此,我们认为的第一种方法是创建一个聚合来保存所有约会,并负责安排它们,但是这个聚合会很大并且在技术上是不可接受的。

第二种方法,也是目前的方法,是将 Appointment 创建为 Aggregate Root,然后使用查询读取端的域服务(域层中的接口和基础层中的实现)对其进行验证。

今天的样子:

  • 在命令处理程序中,实例化新的 Appointment,在其构造函数中传递一个域服务

  • 约会调用域服务,它查询读取端并验证规则。但是,这里可能会出现竞争条件(同时安排两个约会,因为两者看不到对方,所以都将被创建)。

  • 如果域服务验证规则,则创建约会,但状态为 PENDING,并触发域事件 AppointmentRequested。

  • 在读取端,订阅了此事件,并且在读取的数据库中插入了一个投影(状态 = PENDING)。在同一个事务中,一个命令 CompleteAppointmentSchedule 被插入到我的发件箱中,并很快被写入方异步发送和接收。

  • 写端处理调用约会.CompleteSchedule(domainService) 的命令。实例化新约会时传递的相同域服务再次传递给约会。但是,现在,约会已经在读取数据库中,并且可以检查业务规则。

以这种方式使用读取端是否正确?如果不使用读取端,我们无法想出另一种方法来检查此规则。一位团队成员建议我们可以为我们的写入端创建一个私有读取端,并在这些情况下使用它而不是读取端,但是,当我们使用 EventStore DB 时,我们将不得不创建另一个数据库,如我们在读取端 (pgsql) 上使用,以便能够在这个私有读取端这样做。

【问题讨论】:

  • 您可以使用 SAGA 进行管理。发布了两个 AppointmentCreated 事件,那么你需要更新读取端,但是在读取端,你有唯一的约束,所以其中一个无法保存,然后发布另一个事件以取消第二个 AppointmentCreated 事件

标签: domain-driven-design race-condition cqrs event-sourcing


【解决方案1】:

我正在构建一个用于管理健康诊所的应用程序。

预订办公室,召集整个团队,观看Trench Talk: Evolving a Model。 Yves Reynhout 一直在做(并谈论)领域驱动设计,他的领域是医疗保健的预约安排。

安排约会时,需要验证一些业务规则:

  • 不能与同一医生或同一患者安排在同一时间
  • 医生一周内一个月只能参加N次预约,
  • 医生只能参加 N 次预约

您需要与您的领域专家讨论的事情之一;您需要防止调度冲突,还是需要识别调度冲突并解决它们?

推荐阅读:


也就是说,你真的很接近一个共同的答案。

您对日历的缓存副本进行检查,以避免最常见的冲突(请注意,当您在检查时间表的同时其他人试图取消冲突时,仍然存在竞争条件预约)。然后,您将预约请求消息放入队列中。

订阅队列是一种服务即SOA,它是所有与调度相关的信息的技术权威。该服务有自己的数据库,并在提交更改之前检查自己的所有权威副本。

这里的关键区别在于,当服务直接使用数据的锁定实例时。这可能是因为服务中的事件处理程序是唯一对权威数据具有写入权限的进程(并且它本身一次只处理一条消息),或者可能是因为事件处理程序锁定了 all em> 必要的数据,以确保写入的结果仍然符合业务规则(冲突的写入竞争同一个锁,从而确保数据更改得到控制)。

实际上,所有更改权威日历数据的尝试都(逻辑上)序列化,以确保写入不会相互冲突。

在 CQRS 语言中,所有这些锁定都发生在日历服务的 write 模型中。其他人都使用读取模型提供的未锁定数据副本(在将数据更改从写入模型复制到读取模型时涉及一些适度的管道)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多