【问题标题】:Creation Concurrency with CQRS and EventStore使用 CQRS 和 EventStore 创建并发
【发布时间】:2012-07-01 06:30:57
【问题描述】:

基线信息: 我正在使用外部 OAuth 提供程序进行登录。如果用户登录到外部 OAuth,他们可以进入我的系统。但是,此用户可能尚不存在于我的系统中。这不是真正的技术问题,但我使用 JOliver EventStore 是物有所值。

逻辑:

  1. 我没有为新用户提供指南。我只有一个电子邮件地址。
  2. 我在发送命令之前检查我的读取模型,如果用户电子邮件 存在,我发出一个带有 ID 的登录命令,如果不存在,我发出一个 具有生成 ID 的 CreateUser 命令。我的问题是新用户的情况。
  3. 使用新 ID 在事件存储中进行保存。

问题: 假设由于浏览器刷新或在实现与读取模型的一致性之前发生的一些其他异常,在读取模型更新之前以某种方式发出了两个创建命令。没关系,这不是我的问题。

会发生什么: 因为新 ID 是一个 Guid 梳,所以事件存储不可能知道这两个 CreateUser 命令代表同一个用户。当他们到达读取模型时,读取模型将知道(因为他们有相同的电子邮件)并且可以合并两条记录或采取其他一些补偿措施。但是现在我的读取模型与事件存储不同步,事件存储仍然认为这是两个独立的实体。

也许没关系,因为:

  1. 重放事件将对读取模型产生相同的影响 所以应该没问题。
  2. 因为这两个命令是重复的“创建”命令,它们应该包含相同的信息,所以我不会丢失事件存储中的任何内容。

谁能说明他们是如何处理类似问题的?如果需要进行一些补偿操作,读取模型服务是否会在意识到它有重复条目时发出某种补偿命令?有没有我没有考虑的更简单的方法?

【问题讨论】:

    标签: cqrs event-sourcing neventstore


    【解决方案1】:

    您非常接近我认为可能的适当解决方案。如果我可以总结一下,这个场景有点像这样:

    • 执行 OAuth 提示。
    • 使用阅读模型根据电子邮件地址在经常访问者和新访问者之间做出决定。
    • 如果是新访客,请发送 RegisterNewVisitor 命令消息,该消息会被处理并存储在 eventstore 中。
    • 假设有一些并发发生,对于同一个电子邮件地址,会导致两条 RegisterNewVisitor 消息,每条消息都包含系统认为与电子邮件地址关联的密钥。这些键(guid)是不同的。
    • 在读取模型中检测到此重复键问题,并将两个读取模型记录合并为一条记录。

    现在,与其合并读取模型中的记录,不如向您的域模型发送 ResolveDuplicateVisitorEmailAddress { Key1, Key2 },将其留给域模型(要采取的业务决策的编码形式)来解决这个问题。你甚至可以有一个专门的读取模型来处理这类问题,另一个读取模型只会获得一种 DuplicateVisitorEmailAddressResolved 事件,并将其投影到适当的记录中。

    警告:您提出了一个技术问题,而我为您提供了一个技术性的、可能的解决方案。一般来说,我不会应用这种技术,除非我有一些值得投资的业务指标(用户第一次同时登录的频率是多少 - 也许以这种方式解决它只是一种忽略根本原因的方法(flakey OAuth,没有注册新的访问者进程等))。这个问题还有其他技术解决方案,但我想给你一个最接近你已有的解决方案。它们的范围从按顺序注册新访问者到保留尚未在读取模型中的访问者的内存投影。

    【讨论】:

    • 我的意思是,如果您采取这种行动,这是属于领域模型的决定。
    • 只是为了完整 - 这已经讨论过多次 - codebetter.com/gregyoung/2010/08/12/…
    • 回答得很好,感谢您对该主题的了解。我敢肯定,这已经被回答了很多次,但是对于 CQRS,通常很难找到明确的答案,因为它们是如此分散。我也同意我可能过于复杂化了一个无关紧要的情况。在这种情况下,我可能不需要做任何事情,但在我确实需要解决这个问题的情况下,这个案例本身引发了更多的“方法问题”。感谢您的回答和链接。
    猜你喜欢
    • 1970-01-01
    • 2016-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多