DDD+CQRS+EventSourcing 如何确保预测是最新的?

问题描述 投票:0回答:1

我们开发使用

DDD
CQRS+Eventsourcing
的应用程序。

我们有一个

UserAggregate
。该聚合使用
UserMailIndex
UserMailIndex
- 是一个投影,它只是唯一电子邮件的列表。每次当
userCreated
事件推送到事件存储时,投影机都会读取该事件,并将邮件添加到
UserMailIndex

UserAggregate
收到命令
CreateUser{Mail = ..., Name = ... etc.}
时,聚合会在
CreateUser.Mail
中查找
UserMailIndex
以确保邮件之前未被使用过。如果没有使用,
UserAggregate
会产生事件
UserCreated

public class UserAggregate
{
    private UserMailIndex _mailIndex;
    UserAggregate(UserMailIndex mailIndex)
    {
        _mailIndex = mailIndex;
    }
    ...
    public void CreateUser(string userMail)
    {
        if(_mailIndex.Contains(userMail))
            return;
        Apply(UserCreatedEvent(userMail));
    }
}
public class UserMailIndex
{
    public void When(UserCreatedEvent evnt)
    {
        index.Add(evnt.Mail);
    }
}

如何确保

UserMailIndex
是最新的? 如果投影仪没有时间更新
UserMailIndex
投影怎么办? 如果我理解正确的话,这样的架构是基于最终一致性的。

有哪些方法可以确保投影是最新的? 或者哇来决定差距是否“足够小”?

aggregate domain-driven-design projection cqrs event-sourcing
1个回答
0
投票

此问题扩展到任何缓存数据场景,包括投影物化视图和所有索引场景。当我们试图防止数据重复并且您有一个作为事实来源的存储时,唯一的Critical途径是插入/创建数据的实际过程,这也应该是引发create的唯一途径 活动。

第一个问题是您的模式描述的事件源实际上并不“知道”它所描述的事件是否确实发生。您故意向模型添加额外的不确定性,从而使事情变得复杂。如果您首先引发

UserCreated
事件,并且实际的创建过程失败,那么引发该事件实际上已经破坏了 最终一致性 的链,除非其他进程尝试并成功创建用户。

因此从这里开始,实际的

CreateUser
过程(而不是消息)需要确保邮箱是唯一的。这可能是一个 SQL 或其他可以确保原子性和唯一性的后端,也可能是一个外部系统,如果存在重复,则返回失败结果。

  • 这个实际过程,即创建必须是唯一的记录的过程,这是应该引发
    UserCreated
    事件的过程。

为了支持最终一致性,我们不仅允许,而且我们预计会发生这些失败,因为我们知道我们的预测或索引将始终在某种程度上过时。缓存始终是前一个时间点状态的副本,它永远不是“现在”的快照

因此,我们应该预期

CreateUser
命令将为同一用户多次调用,但它应该只引发
UserCreated
事件一次,即第一次实际成功创建用户时。

如何确保

UserMailIndex
是最新的?如果投影仪没有时间更新
UserMailIndex
投影怎么办?

你不要尝试,我们那不是真的,系统效率取决于投影是否保持最新。但重要的是要将你的想法从“可能会失败”转变为“预计有时会失败”。缓存的目的是减少到底层存储的往返,但不是完全取代或阻止它们。

  • 由于重复而无法创建用户并不是例外,它应该是您逻辑中的预期路径。

因此,当

CreateUser
进程失败时,由于用户已经存在,为了支持最终一致性,您可能会选择忽略此错误,或者更改逻辑以使用新消息详细信息更新用户,但重要的是您不会提出
UserCreated
事件。

或者如何判断间隙是否“足够小”?

如何决定是你的IP并取决于你的应用程序域,但是

的简单模型
  1. 尝试创建
  2. 如果存在则更新

适用于任何尺寸的间隙。这可能意味着到商店的一些冗余往返行程非常小,但这是最终一致性的一般权衡,没有可接受的间隙大小,我们必须始终更新以确保一致性,除非解决方案的其余部分允许您假设可以容忍一定的间隙大小。

© www.soinside.com 2019 - 2024. All rights reserved.