4

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

逻辑:

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

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

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

也许没关系,因为:

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

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

4

1 回答 1

7

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

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

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

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

于 2012-06-30T11:17:22.760 回答