Domain driven design 偶尔连接的CQRS系统

Domain driven design 偶尔连接的CQRS系统,domain-driven-design,cqrs,event-sourcing,eventstoredb,occasionallyconnected,Domain Driven Design,Cqrs,Event Sourcing,Eventstoredb,Occasionallyconnected,问题: 两名员工(A&B)在编辑customer#123(比如版本#20)时同时下线,而在下线时继续进行更改 场景: 1-两名员工编辑customer#123并更改一个或多个相同的属性 2-两名员工编辑customer#123,但不进行相同的更改(他们相互交叉而不接触) 。。。然后他们都在线返回,首先是员工A追加,从而将客户更改为版本21,然后是员工B,仍然是版本20 问题: 在场景1中,我们要保留哪些更改 我们可以在场景2中进行合并吗 上下文: 1-CQRS+事件来源风格系统 2-将事件源数据

问题:

两名员工(A&B)在编辑customer#123(比如版本#20)时同时下线,而在下线时继续进行更改

场景:

1-两名员工编辑customer#123并更改一个或多个相同的属性

2-两名员工编辑customer#123,但不进行相同的更改(他们相互交叉而不接触)

。。。然后他们都在线返回,首先是员工A追加,从而将客户更改为版本21,然后是员工B,仍然是版本20

问题:

在场景1中,我们要保留哪些更改

我们可以在场景2中进行合并吗

上下文:

1-CQRS+事件来源风格系统

2-将事件源数据库用作队列

3-读取模型的最终一致性

4-RESTful API

编辑-1:根据迄今为止的答案进行澄清:

为了执行细粒度的合并,我需要对表单中的每个字段使用一个命令,例如

上面,针对ChangeName、ChangeSupplier、ChangeDescription等的细粒度命令,每个命令都有自己的时间戳,允许在A和B都更新了ChangedName的情况下自动合并

编辑-2:根据特定事件存储的使用情况进行跟进:

似乎我将使用@GetEventStore来持久化我的事件流

它们使用乐观并发,如下所示:

  • 流中的每个事件使流版本增加1

  • 写入可以使用写入程序上的ES ExpectedVersion标头指定预期版本

    • -1指定流不应该已经存在

    • 0及更高版本指定流版本

    • 如果流不在版本中,则写入将失败,您可以使用新的预期版本号重试,或者重新处理该行为,并决定如果您选择这样做,则写入将失败

  • 如果未指定预期版本,则禁用乐观并发控制

  • 在此上下文中,乐观并发性不仅基于消息ID,还基于事件#


    • 以下是一些解决方案的一般概述:

      情景1 必须有人来决定,最好是人。您应该询问用户或表明存在冲突

      Dropbox通过拾取后面的文件并将file.conflict文件保留在同一目录中供用户删除或使用来解决此问题

      情景2 保留原始数据,查看哪些字段实际发生了更改。然后,您可以应用员工1的更改,然后再应用员工2的更改,而无需任何干预

      场景3(仅当更改在不同时间上线时)
      让第二个用户知道他们脱机时发生了更改。尝试场景2并向第二个用户显示新结果(因为这可能会更改他的输入)。然后询问他是否要保存更改、先修改更改或将其丢弃。

      如果我正确理解了您的设计图,则偶尔连接的用户会将命令(即更改请求)排队,当用户重新连接时,排队的命令会一起发送;只有一个数据库权限(命令处理程序查询该权限以加载其aggretate的最新版本);只有视图模型与客户端同步

      在此设置中,场景2由您的设计自动合并,如果您明智地选择了命令,请阅读:使它们细粒度化:对于每个可能的更改,选择一个命令。然后,在客户端重新连接时,命令按任意顺序处理,但由于它们只影响不相交字段,因此没有问题:

    • 客户在v20
    • A处于脱机状态,根据v20的过时模型编辑更改
    • B处于脱机状态,根据v20的过时模型编辑更改
    • A联机,批处理发送一个排队的
      ChangeName
      命令,v20的客户被加载并作为v21持久化
    • B联机,batch发送一个排队的
      ChangeAddress
      命令,v21的客户被加载并作为v22持久化
    • 数据库包含的用户具有正确的名称和地址,如预期的那样
    • 场景1中,使用此设置,两名员工将覆盖其他员工的更改:

    • 客户在v20
    • A处于脱机状态,根据v20的过时模型编辑更改
    • B处于脱机状态,根据v20的过时模型编辑更改
    • A联机时,batch向“John Doe”发送一个排队的
      ChangeName
      命令,v20的客户被加载并持久化为名为“John Doe”的v21
    • B联机时,batch向“Joan d'Arc”发送排队的
      ChangeName
      命令,v21(名为“John Doe”)的客户被加载并持久化为v22(名为“Joan d'Arc”)
    • 数据库包含名为“Joan d'Arc”的用户
    • 如果B在A之前在线,则反之亦然:

    • 客户在v20
    • A处于脱机状态,根据v20的过时模型编辑更改
    • B处于脱机状态,根据v20的过时模型编辑更改
    • B联机时,batch向“Joan d'Arc”发送排队的
      ChangeName
      命令,v20的客户被加载并持久化为v21(名称为“Joan d'Arc”)
    • 当A联机时,batch向“John Doe”发送排队的
      ChangeName
      命令,v21的客户被加载并持久化为名为“John Doe”的v22
    • 数据库包含名为“John Doe”的用户
    • 有两种方法可以启用冲突检测:

    • 检查命令的创建日期(即员工修改的时间)是否在
      客户的上次修改日期之后。这将禁用场景2的自动合并功能,但会