使用CQRS和EventStore创建并发(Creation Concurrency with CQRS and EventStore)

系统教程 行业动态 更新时间:2024-06-14 16:57:41
使用CQRS和EventStore创建并发(Creation Concurrency with CQRS and EventStore)

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

逻辑:

我没有得到新用户的指导。 我只有一个电子邮件地址。 我在发送命令之前检查了我的读取模型,如果用户电子邮件存在,我发出带有ID的登录命令,如果没有,我发出带有生成ID的CreateUser命令。 我的问题是在新用户的情况下。 使用新ID在事件存储中进行保存。

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

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

也许这并不重要,因为:

重播这些事件在读取模型上会产生相同的效果,因此应该可以。 因为这两个命令都是重复的“创建”命令,它们应该包含相同的信息,所以它不像我在事件存储中丢失任何东西。

任何人都可以阐明他们如何处理类似问题吗? 如果某些补偿行为需要发生,读取模型服务会在发现重复条目​​时发出某种补偿命令? 有没有更简单的方法我不考虑?

谢谢!

Baseline info: I'm using an external OAuth provider for login. If the user logs into the external OAuth, they are OK to enter my system. However this user may not yet exist in my system. It's not really a technology issue, but I'm using JOliver EventStore for what it's worth.

Logic:

I'm not given a guid for new users. I just have an email address. I check my read model before sending a command, if the user email exists, I issue a Login command with the ID, if not I issue a CreateUser command with a generated ID. My issue is in the case of a new user. A save occurs in the event store with the new ID.

Issue: Assume two create commands are somehow issued before the read model is updated due to browser refresh or some other anomaly that occurs before consistency with the read model is achieved. That's OK that's not my problem.

What Happens: Because the new ID is a Guid comb, there's no chance the event store will know that these two CreateUser commands represent the same user. By the time they get to the read model, the read model will know (because they have the same email) and can merge the two records or take some other compensating action. But now my read model is out of sync with the event store which still thinks these are two separate entities.

Perhaps it doesn't matter because:

Replaying the events will have the same effect on the read model so that should be OK. Because both commands are duplicate "Create" commands, they should contain identical information, so it's not like I'm losing anything in the event store.

Can anybody illuminate how they handled similar issues? If some compensating action needs to occur does the read model service issue some kind of compensation command when it realizes it's got a duplicate entry? Is there a simpler methodology I'm not considering?

Thanks!

最满意答案

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

执行OAuth-entication。 使用阅读模型根据电子邮件地址决定定期访问者和新访问者。 在新访问者的情况下,发送RegisterNewVisitor命令消息,该消息被处理并存储在事件存储中。 假设有一些并发,对于同一个电子邮件地址,会产生两个RegisterNewVisitor消息,每个消息都包含系统认为是与电子邮件地址关联的密钥。 这些键(guid)是不同的。 在读取模型中检测此重复键问题,并将两个读取的模型记录合并到一个记录中。

现在,为了不将合并记录放入阅读模型中,为什么不向发送域模型发送ResolveDuplicateVisitorEmailAddress {Key1,Key2},并将其留给域模型(编制的业务决策形式)来解决此问题。 您甚至可以使用专用的读取模型来处理这类问题,另一个读取模型只会获得一种DuplicateVisitorEmailAddressResolved事件,并将其投影到正确的记录中。

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

You're very close to what I'd consider a proper possible solution. The scenario, if I may summarize, is somewhat like this:

Perform the OAuth-entication. Using the read model decide between a recurring visitor and a new visitor, based on the email address. In case of a new visitor, send a RegisterNewVisitor command message that gets handled and stored in the eventstore. Assume there is some concurrency going on that, for the same email address, causes two RegisterNewVisitor messages, each containing what the system thinks is the key associated with the email address. These keys (guids) are different. Detect this duplicate key issue in the read model and merge both read model records into one record.

Now instead of merging the records in the read model, why not send a ResolveDuplicateVisitorEmailAddress { Key1, Key2 } towards your domain model, leaving it up to the domain model (the codified form of the business decision to be taken) to resolve this issue. You could even have a dedicated read model to deal with these kind of issues, the other read model will just get a kind of DuplicateVisitorEmailAddressResolved event, and project it into the proper records.

Word of warning: You've asked a technical question and I gave you a technical, possible solution. In general, I would not apply this technique unless I had some business indicator that this is worth investing in (what's the frequency of a user logging in concurrently for the first time - maybe solving it this way is just a way of ignoring the root cause (flakey OAuth, no register new visitor process in place, etc)). There are other technical solutions to this problem but I wanted to give you the one closest to what you already have in place. They range from registering new visitors sequentially to keeping an in-memory projection of the visitors not yet in the read model.

更多推荐

本文发布于:2023-04-13 12:53:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/dzcp/feb0131236bd845cff9c6d54e42c6be2.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:EventStore   CQRS   Concurrency   Creation

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!