如果域事件失败怎么办?
What if domain event failed?
我是 DDD 新手。现在我在看领域事件。我不确定我是否正确理解了这个领域事件,但我只是在想如果领域事件发布失败会发生什么?
我这里有一个案例。当买家从我的网站订购商品时,首先我们将创建一个对象,Order with line of items。将发布域事件 OrderWasMade 以扣除 Inventory 中的库存。所以是这样的情况,如果当事件被处理时,项目数量将被扣除,但是如果当系统尝试扣除库存时,它发现该项目没有剩余库存(amount = 0)怎么办? .因此,无法扣除项目金额,但已经提交了订单。
会不会出现这种情况?
很抱歉在这里打扰另外 2 个问题。
好像每个事件都在自己的事务范围内,这意味着系统需要同时打开多个数据库连接。所以如果我使用 IIS 服务器,我必须启用 DTC,我说得对吗?
domain-events和domain-services有关系吗?
领域事件永远不会失败,因为它是对已发生事情的通知(注意过去时)。但是将生成该事件的操作 可能会 失败并且不会生成该事件。
您告诉我们的场景表明您实际上并没有在进行 DDD,而是在使用 DDD 词汇进行 CRUD。是的,我知道你是新手,别担心,每个人在掌握它之前都误解了 DDD(但这可能需要一些时间和大量练习)。
DDD 是识别领域模型抽象,不是代码。代码是您实现该抽象的时候。很明显你没有做正确的建模,因为领域专家应该告诉你如果产品缺货会发生什么。
接下来,此级别没有 db/acid 笔交易。这些是实现细节。 DDD 的工作方式是确定业务需要在哪些方面保持一致,这称为 聚合 。
订单已提交,此时该用例停止。当您发布 OrderWasMade
事件时,会触发另一个用例(扣除库存或其他)。这是一个 不同的 业务场景,但不属于 "submit order" 的一部分。如果库存不足,则会发布另一个事件 NotEnoughInventory
并触发另一个用例。我们在这里跟踪业务,并确定业务为完成订单所做的每个步骤。
DDD 的艺术在于理解和识别细粒度的业务功能、涉及的聚合、做出决策的业务行为等,这与数据库或事务无关。
在 DDD 中,聚合是唯一需要使用工作单元的地方。
回答您的问题:
It seems like each event will be in its own transaction scope, which means the system requires to open multiple connection to database at once. So if I am using IIS Server, I must enable DTC, am I correct?
不,事务、事件和分布式事务是不同的东西。 IIS是web服务器,我想你要说的是SqlServer。您总是在 Web 应用程序中打开与数据库的多个连接,DTC 与它无关。实际上,这个问题告诉我你需要阅读更多关于 DDD 而不仅仅是 Evans 的书。老实说,从 DDD pov 来看,你的要求没有多大意义。你知道 DD 的原则之一:数据库(如持久性细节)不存在。
Is there any relationship between domain-events and domain-services
他们都是域的一部分,但他们有不同的角色:
- 域事件告诉世界域中发生了一些变化
- 领域服务封装了没有自己持久化状态的领域行为(如计算税)
通常,应用程序服务(充当业务用例的主机)将使用域服务来验证约束或收集更改聚合所需的数据,而聚合又会生成一个或多个事件。聚合是持久化的,聚合以原子方式持久化,即数据库事务/工作单元。
what will happen if domain event published failed?
MikeSW 已经对此进行了描述 - 发布事件(也就是说,使其成为历史的一部分)与使用事件是分开的。
what if when the system try to deduct the stock, it found out that there is no stock remaining for the item (amount = 0). So, the item amount can't be deducted but the order had already being committed.
Will this kind of scenario happen?
所以 DDD 的答案是:请教您的领域专家!
如果您与您的领域专家坐下来,探索无处不在的语言,您可能会发现这是订购的快乐路径的一个很好理解的例外,具有理解的缓解措施(“我们将状态标记为订单处于待处理状态,我们会检查是否已经从供应商处订购了更多存货……”)。这基本上是一个需求发现练习。
当你理解这些要求后,你就去做。
Go do it 通常表示“saga”(对该术语的误导和过度使用);跟踪正在发生的事情的业务 process/workflow/state 机器实现。
使用您的示例:OrderWasMade 触发 OrderFulfillment 流程,该流程跟踪订单的“状态”。例如,可能存在“AwaitingInventory”状态,其中 OrderFulfillment 停放直到供应商的下一次交货。
推荐阅读:
如果您需要库存始终保持一致,在事件源系统中处理此问题的常用方法(也可以在非基于事件的系统中,这是正交)是在事件存储级别依赖乐观锁定。
事件基本上有一个修订号,他们希望事件流在该修订号生效。一旦事件到达持久存储,就会根据实际流号检查其修订号,如果它们不匹配,则会引发冲突异常并中止事务。
正如@MikeSW 指出的那样,根据您的业务需求,库存检查可以是一个以最终一致的方式处理问题的带外流程。 最终的范围可以从流程的另一部分立即接管时的几毫秒到发送电子邮件时需要采取人工操作的小时。
换句话说,如果您的领域需要,您可以选择交易这一系列事件
(OrderAbortedOutOfStock)
为
(OrderMade, <-- Some amount of time --> OrderAbortedOutOfStock)
最终达到相同的聚合状态
我是 DDD 新手。现在我在看领域事件。我不确定我是否正确理解了这个领域事件,但我只是在想如果领域事件发布失败会发生什么?
我这里有一个案例。当买家从我的网站订购商品时,首先我们将创建一个对象,Order with line of items。将发布域事件 OrderWasMade 以扣除 Inventory 中的库存。所以是这样的情况,如果当事件被处理时,项目数量将被扣除,但是如果当系统尝试扣除库存时,它发现该项目没有剩余库存(amount = 0)怎么办? .因此,无法扣除项目金额,但已经提交了订单。
会不会出现这种情况?
很抱歉在这里打扰另外 2 个问题。
好像每个事件都在自己的事务范围内,这意味着系统需要同时打开多个数据库连接。所以如果我使用 IIS 服务器,我必须启用 DTC,我说得对吗?
domain-events和domain-services有关系吗?
领域事件永远不会失败,因为它是对已发生事情的通知(注意过去时)。但是将生成该事件的操作 可能会 失败并且不会生成该事件。
您告诉我们的场景表明您实际上并没有在进行 DDD,而是在使用 DDD 词汇进行 CRUD。是的,我知道你是新手,别担心,每个人在掌握它之前都误解了 DDD(但这可能需要一些时间和大量练习)。
DDD 是识别领域模型抽象,不是代码。代码是您实现该抽象的时候。很明显你没有做正确的建模,因为领域专家应该告诉你如果产品缺货会发生什么。
接下来,此级别没有 db/acid 笔交易。这些是实现细节。 DDD 的工作方式是确定业务需要在哪些方面保持一致,这称为 聚合 。
订单已提交,此时该用例停止。当您发布 OrderWasMade
事件时,会触发另一个用例(扣除库存或其他)。这是一个 不同的 业务场景,但不属于 "submit order" 的一部分。如果库存不足,则会发布另一个事件 NotEnoughInventory
并触发另一个用例。我们在这里跟踪业务,并确定业务为完成订单所做的每个步骤。
DDD 的艺术在于理解和识别细粒度的业务功能、涉及的聚合、做出决策的业务行为等,这与数据库或事务无关。
在 DDD 中,聚合是唯一需要使用工作单元的地方。
回答您的问题:
It seems like each event will be in its own transaction scope, which means the system requires to open multiple connection to database at once. So if I am using IIS Server, I must enable DTC, am I correct?
不,事务、事件和分布式事务是不同的东西。 IIS是web服务器,我想你要说的是SqlServer。您总是在 Web 应用程序中打开与数据库的多个连接,DTC 与它无关。实际上,这个问题告诉我你需要阅读更多关于 DDD 而不仅仅是 Evans 的书。老实说,从 DDD pov 来看,你的要求没有多大意义。你知道 DD 的原则之一:数据库(如持久性细节)不存在。
Is there any relationship between domain-events and domain-services
他们都是域的一部分,但他们有不同的角色:
- 域事件告诉世界域中发生了一些变化
- 领域服务封装了没有自己持久化状态的领域行为(如计算税)
通常,应用程序服务(充当业务用例的主机)将使用域服务来验证约束或收集更改聚合所需的数据,而聚合又会生成一个或多个事件。聚合是持久化的,聚合以原子方式持久化,即数据库事务/工作单元。
what will happen if domain event published failed?
MikeSW 已经对此进行了描述 - 发布事件(也就是说,使其成为历史的一部分)与使用事件是分开的。
what if when the system try to deduct the stock, it found out that there is no stock remaining for the item (amount = 0). So, the item amount can't be deducted but the order had already being committed.
Will this kind of scenario happen?
所以 DDD 的答案是:请教您的领域专家!
如果您与您的领域专家坐下来,探索无处不在的语言,您可能会发现这是订购的快乐路径的一个很好理解的例外,具有理解的缓解措施(“我们将状态标记为订单处于待处理状态,我们会检查是否已经从供应商处订购了更多存货……”)。这基本上是一个需求发现练习。
当你理解这些要求后,你就去做。
Go do it 通常表示“saga”(对该术语的误导和过度使用);跟踪正在发生的事情的业务 process/workflow/state 机器实现。
使用您的示例:OrderWasMade 触发 OrderFulfillment 流程,该流程跟踪订单的“状态”。例如,可能存在“AwaitingInventory”状态,其中 OrderFulfillment 停放直到供应商的下一次交货。
推荐阅读:
如果您需要库存始终保持一致,在事件源系统中处理此问题的常用方法(也可以在非基于事件的系统中,这是正交)是在事件存储级别依赖乐观锁定。
事件基本上有一个修订号,他们希望事件流在该修订号生效。一旦事件到达持久存储,就会根据实际流号检查其修订号,如果它们不匹配,则会引发冲突异常并中止事务。
正如@MikeSW 指出的那样,根据您的业务需求,库存检查可以是一个以最终一致的方式处理问题的带外流程。 最终的范围可以从流程的另一部分立即接管时的几毫秒到发送电子邮件时需要采取人工操作的小时。
换句话说,如果您的领域需要,您可以选择交易这一系列事件
(OrderAbortedOutOfStock)
为
(OrderMade, <-- Some amount of time --> OrderAbortedOutOfStock)
最终达到相同的聚合状态