问题标签 [event-sourcing]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
3 回答
1670 浏览

domain-driven-design - 事件溯源链事件

我正在使用事件源实现有界上下文,但遇到了问题。假设我正在模拟一场足球比赛,我对个人进球(谁进球等)和总分都感兴趣。因此,如果我有一个 Match 聚合根,理想情况下我希望引发名为 GoalScored 和 ScoreChanged 的​​事件。我希望像这样从域中明确说明分数的原因是我不希望许多不同的侦听器和可能的其他有界上下文都计算相同的东西。

这看起来很简单,但是:Match 对象有一个添加新目标的 Goal() 方法。本着事件溯源的精神,这不会直接改变 Match 状态,而是引发一个 GoalScored 事件,该事件在 Match 中处理,然后改变状态(以及被推送到非规范化器的事件)。因此,就提高 ScoreChanged 而言,在处理 GoalScored 事件之前,分数实际上并没有改变,所以我是否应该引发另一个事件来响应该事件 (ScoreChanged),从而有效地链接事件?我不这么认为,首先,当从事件存储重新加载聚合根时,每次都会创建大量额外事件以响应每个 GoalScored。

我还考虑过在引发 GoalScored 的命令处理程序中计算得分,这是一种“假设”的情况。然后我可以在命令处理程序中引发这两个事件。不过,我真的不想那样做——它看起来并不“正确”。计算分数对于足球来说很简单,但其他游戏(例如板球)需要更多的工作。

我可以将目标和得分都放在 GoalScored 事件中,这很公平,但又似乎不对 - 得分与 GoalScored 事件本身无关。

讨论事件溯源时使用的所有示例似乎都使用电子商务客户/订单域,而我从未见过与此类似的案例。

有没有人有处理这种情况的经验?

谢谢

0 投票
1 回答
834 浏览

.net - 在没有事件存储的服务总线上重放事件

我正在尝试设计一项新服务并尝试遵循 CQRS。我将 ORM (NHibernate) 用于读写模型。除此之外,写入模型不是事件来源的。我的目标是首先让技术保持熟悉,然后在读取端迁移到 NoSQL,在写入端迁移到事件源。

我希望使用服务总线,我可以通过重放旧事件来生成新的读取模型;但是我现在卡住了。我有几个问题:

  1. 我想要完成的事情有什么意义吗?如果是这样,我可以使用“Windows Server 服务总线”来执行此操作吗?我找不到一种方法来创建一个新的订阅并让光标从一个主题的开头开始。当所有现有订阅者都使用它们时,是否会清除事件?

  2. 如果有意义但“Windows Server的服务总线”不能胜任这项工作,您是否建议寻找替代服务总线或在写入端实现事件源?

0 投票
1 回答
2247 浏览

import - CQRS/ES:批量操作/导入

我正在尝试围绕整个 CQRS/ES 想法进行思考,并考虑编写一个概念证明和技术规范,说明如何在我们当前的应用程序中实现它。

有问题的操作(在如何将它们映射到 CQRS/ES 方面)是通过文件导入批量更新复杂的文章数据——数据文件中的单行扩展到文章组、文章、标题、单位和属性、批量-加载将买方分类链接到供应商分类的文件,并导出部分或整个分类。

我在某处(可能是 DDDCQRS Google Group)读到,为文章导入 BC(读取 Excel 文件或其他网格文件)建模的最佳方法是将单行导入数据汇总,然后整个导入成为聚合根。这样,在解析文件之后,我所要做的就是创建一个导入聚合,并为每一行添加该行到导入。这会将事件存储在 BC 的事件存储中,并发布文章管理 BC 将订阅的事件。这有意义吗?

在当前系统中,导入在单个长时间运行的事务中运行。长时间运行应该在 5 到 40 分钟之间读取,具体取决于导入的数据量和给定用户已经存在的数据量(因为数据与先前导入的文件和当前数据进行比较)。当操作中途失败时,当前整个操作被回滚。这在 CQRS/ES 中是如何工作的?

0 投票
2 回答
960 浏览

cqrs - 在 Event Store / CQRS 架构中,为什么存储事件而不是命令?

假设我们可以通过应用相同的命令集来恢复状态,那么为什么不简单地存储命令而不是事件呢?

0 投票
1 回答
301 浏览

cqrs - 克服事件存储中不良/不一致数据的最佳方法是什么?

事件存储应该是仅添加的,您永远不会删除或编辑数据。

就我而言,我们没有禁止用户进行的一些中游更改,并且数据是“坏的”/不一致的......因为他们更改了我们在中游配置的谷歌文档的域名...

我可以从事件存储中重新配置,但该数据已损坏。

我是否应该创建某种突变器,当它从事件存储中提取数据时,修复它?

我需要一些想法在这里!

0 投票
2 回答
977 浏览

oop - DDD、对象图和事件溯源

介绍

这个问题是关于 DDD 和事件溯源,其中聚合中的实体(聚合根除外)具有事件生成行为。

例子

下面是我描述的情况的一个示例,我确定我想在聚合内的其他实体中封装一些逻辑。这可能涉及暂停对实际示例以及它是否是一个好模型的怀疑。:)

我正在尝试对DeliveryRun聚合根 (AR) 建模,这是车辆执行交付的行程。在它离开之前,它必须有一个最新的DeliveryManifest. 它的“最新性”向我表明,它是 AR 定义的一致性边界DeliveryManifest内的一个实体。DeliveryRun

到目前为止还好。

我为此使用了 Event Sourcing 方法 - Greg Young教授并在Regalo 库中实施的方法。这意味着如果 AR ( DeliveryRun) 没有任何行为,则它们实际上不需要任何实体(例如,aSalesOrder可能没有SalesOrderLines,因为它记录了诸如ItemsAdded/之类的事件ItemsRemoved)。

但是,围绕DeliveryManifest. 具体来说,一旦首次请求清单,当项目被添加到交付时,需要创建清单的新版本。这意味着我们可以确保司机在没有可用的最新清单的情况下不会离开。

如果我要将逻辑封装在DeliveryManifest对象内部(不会被序列化和存储;我们使用的是事件源,它不是 AR),我如何捕获事件?

我正在考虑的选项

  • 事件是否应该由DeliveryManifest实体生成,但针对DeliveryRun自身保存(然后需要知道如何将这些事件重播到DeliveryManifest从事件存储加载时)?

  • 是否应该没有DeliveryManifest(可能作为数据结构除外)并且所有逻辑/事件都由DeliveryRun?

  • 是否应该DeliveryManifest是它自己的 AR 并确保DeliveryRun被告知当前清单的 ID?由于这将清单对象置于 的一致性边界之外DeliveryRun,因此我需要构建一些事件处理来订阅DeliveryRun与清单相关的更改,以便可以相应地更新/无效等。

  • 实现与 Udi 的 DomainEvents 模式类似的不同样式来捕获事件。这意味着更改 Regalo 库,尽管我认为它可以很容易地支持这两种模式。这将允许捕获聚合中所有实体生成的所有事件,以便针对 AR 保存它们。我需要考虑一个加载/重播的解决方案......

0 投票
1 回答
448 浏览

domain-driven-design - 如何在分布式事件源系统中对逻辑进行版本控制

例子

我的分布式事件源系统模拟了一段时间内建造和购买的房屋。为简单起见,我们将使用年份作为分布式时钟值(暂时忘记矢量时钟)。

房屋在系统版本 1 中建造需要 1 年,但在版本 2 中需要两倍的时间。这是逻辑上的变化,而不是结构上的变化。

为了应对这种变化,版本 1 中记录的事件也必须在重建状态/快照时由版本 1 重放。当达到第 2 版日志时,应用程序切换到第 2 版逻辑并继续重播剩余事件。构建了一个有效的快照。

问题

我的分布式系统中的节点将在不同时间更新到版本 2,从而创建一个多个版本同时运行的窗口。我目前的理解是,这个窗口只能通过功能切换等技术来减少,但不能完全删除(除非您通过关闭整个系统进行升级而牺牲可用性)。

这在合并来自分布式节点的事件日志时会产生问题。事件版本相互渗透,因此无法在重播期间简单地从版本 1 升级到 2。例如:

在不接受所有节点关闭的系统中,这通常是如何处理的?

0 投票
1 回答
922 浏览

domain-driven-design - 聚合必须是强一致的吗?

我在 DDD 上阅读的所有内容都暗示聚合中的状态必须是高度一致的。

这意味着如果需要冗余,则只能使用强一致性复制(例如 2PC、3PC 或 Paxos)。

您是否允许使用最终一致的复制,例如多主或主从?如果您确实使用了它们,那么在 DDD 术语中您仍然拥有“聚合”吗?这是常见的事情吗?

0 投票
2 回答
1161 浏览

domain-driven-design - DDD:继承和事务

我正在尝试领域驱动设计和事件溯源。我打算使用(用 C# 开发)NServiceBus、JOliver 的 EventStore 和 NES 来绑定它们。我已经拥有适用于一个简单案例的基础架构(一个仅包含值对象的聚合根)。

我正在阅读 Evans 蓝皮书,并且正在尝试开发一个简单的域模型,其中的示例取自我的工作领域(HVAC 维护公司的 ERP 和 CRM)。

我正在建模一个简单的子域,即 HVAC 机器和它们之间的关系。机器有多种类型,例如熔炉、燃烧器、空调、压缩机、通用组件。每台机器可以有多个子机器。所有机器类型都有一些共同的数据和一些共同的行为。但是每种类型都有额外的数据和特定的行为,例如,您只能将 Burner 对象添加到 Furnace。

我分析的第一个结果是每台机器都应该是一个聚合根(继承自 NES 中的 AggregateBase),因为它必须能够保存对特定机器的引用(例如,用于插入涉及单台机器的维修记录、故障记录、等),并且还可以减少大型机器树中的并发问题。

因此,我的假设如下:

但我有一些疑问:

  1. 这是代表我的域的正确方法吗?我读到不鼓励类继承,但这在我看来是使用它的完美案例(燃烧器是机器,炉子也是)。我将仅限于一级继承。

  2. 是否可以使用 Event Sourcing 实现类继承?特别是建议的技术堆栈(nServiceBus、EventStore、NES)?

  3. 我应该如何执行添加子机器(例如燃烧器到炉子)?这个操作可以分为两种:

    1. 将新的 Burner 添加到 Burner 存储库。
    2. 将 Burner 的引用添加到父 Furnace 的 burners 列表但是这两个操作全局修改了两个聚合根,因此该操作应该在两个单独的 commandhandlers/transactions 中执行...但是第二个取决于第一个...是这是一些建模错误的证据吗?我可以将 nServicebusMessages 批处理在一起以在单个事务中执行操作,但我读到这不好......

    如果我让子机器引用父机器,则父机器会丢失子机器列表(验证所需的),我无法查询事件源存储库以获取除 Guid 之外的其他属性。

提前感谢您对讨论的任何贡献,

0 投票
1 回答
625 浏览

domain-driven-design - CQRS/ES - 改变两个聚合

我的 DDD 有问题。我刚开始使用它,所以我没有很多经验。有两个有界上下文:维护和客户端。每个客户都有一个引擎部件的列表。维修中存储了从事维修工作的公司。客户可以为每个部分选择首选公司。
管理员可以暂停公司。两个聚合有变化。首先,它会改变公司状态,并且应该从喜欢它的客户中删除下一家公司。处理它的最佳模式是什么?我可以在聚合中创建两个处理程序,但是当其中一个处理程序抛出异常时,我如何回滚更改?