我们正在使用 CQRS + ES。 ES 是 NEventStore(以前称为 JOliver EventStore)。我们在不同的命令中有 2 个聚合。第二个 AR 的投影取决于读取模型中第一个 AR 投影写入的数据。问题是,当我们运行软件时,一切都进行得如此之快,以至于有时两个聚合会以相同的日期时间(CommitStamp 列)持久保存在事件存储中。重播事件时,我们从头开始按 CommitStamp 列排序。但是,如果两个流具有相同的 CommitStamp 并且以错误的顺序获取,则读取模型投影会出现异常。
知道如何解决这个问题吗?
===============================
这是github上关于这个问题的讨论https://github.com/NEventStore/NEventStore/issues/170 https://github.com/NEventStore/NEventStore/issues/170
===============================
EDIT:这就是我们目前重播事件的方式。我搜索了 GetFrom(...) 的工作原理,结果发现 commitstamp 列不用于排序。毕竟没有提交订单。因此,如果我开始重播事件,它可能会返回今天的事件,下一个 2 年前记录的事件,下一个等等
public void ReplayEvents(Action<List<UncommittedEvent>> whatToDoWithEvents, DateTime loadEventsAfterDate)
{
var eventPortion = store.Advanced.GetFrom(loadEventsAfterDate);
var uncommitedEventStream = new UncommittedEventStream();
foreach (var commit in eventPortion)
{
foreach (var eventMessage in commit.Events.ToList()))
{
uncommitedEventStream.Append(new UncommittedEvent(eventMessage.Body));
}
}
whatToDoWithEvents(uncommitedEventStream.ToList());
}
在NEventStore中,一致性边界是流。从版本 3.2 开始(正如 @Marijn 提到的,问题 #159 https://github.com/NEventStore/NEventStore/issues/159) CommitSequence 列用于在从所有持久性引擎的流中读取数据时对 CommitMessages(以及其中包含的 EventMessages)进行排序。
EventMessage 的排序是有保证的每个流基础。没有隐含的消息顺序across溪流。由于所选持久性引擎的某些方面而可能发生的任何实际排序都是偶然的,不得依赖。
保证跨流的排序将严重限制库的分布式友好方面。即使我们要考虑这样的功能,它也必须与所有支持的持久性引擎一起工作,其中包括 NoSQL 存储。
如果您正在实践领域驱动设计,其中每个流代表一个聚合根,并且您需要保证 2 个或更多聚合之间的排序,则这表明您的领域模型中存在设计问题。
如果您的投影需要合并来自多个源(流)的值,您可以依靠源内排序,但需要灵活地对源间排序。您还应该考虑重复消息的可能性,特别是当您通过外部总线或队列重放时。
如果您尝试使用时间戳 (CommitStamp) 在接收端重新排序多个流,这将是脆弱的。时间戳具有固定的分辨率(毫秒、刻度等)。即使只有一个作家,事情仍然可能“同时”发生。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)