如何使用 Akka 建模聚合关系
How to model aggregates relations with Akka
我在演员模型中挣扎。让我用简单的例子。系统中有两种 actor 类型:Warehouse 和 Item。项目总是分配给特定的仓库。 AddStock 命令允许增加分配给给定仓库位置的库存数量。只有仓库知道自己的位置,因此 Item 必须询问其仓库该位置是否有效才能执行自己的业务逻辑。我想到了一些解决方案
- 命令 AddStock 包含仓库分片区域的 ActorRef,它允许 Item 向仓库询问位置。
- 以某种方式仅允许仓库发出命令 AddStock,该命令允许预先验证位置。不确定如何实现这一点,我考虑过私有命令或一些识别过程
我都不喜欢这两种解决方案。它给简单的任务增加了许多不必要的复杂性。我认为这可能是 OOP 思想的问题,分布式 actor 世界受其自身规则的约束。
在我的场景中,我将 Item 和 Warehouse 视为单独的聚合。它们都被实现为 Persistent Actor(使用 Cluster Sharding)。
只要您假设只有 Warehouse 可以调用 Item::AddStock,一切都很容易。然后 Warehouse 只是在调用之前验证位置。但是可以直接调用 Item 并跳过所有验证。 Item 无法知道调用的仓库是否正确。纯 OOP/DDD 方法很容易实现。项目知道仓库 ID 并且更改数量看起来像这样
item.addStock("L2", 100, warehouse)
知道仓库 id 的项目可以验证所提供的仓库是否为仓库。有仓库可能会询问位置是否有效。我当前的项目处理程序实现:
case AddStock(region, location, quantity) => {
region ? EntityEnvelope(warehouseId, HasLocation(location)) map (
_ => VerifiedAddStock(quantity)
) pipeTo self
VerifiedAddStock 是 Item 的私有对象,所以我确定谁是命令发布者(几乎是因为它不强制执行身份)。
所以问题是如何在 Actor 世界中建模这种关系?绕过分片区域 ref 是规范吗?
有人可能会认为这是由于 aggregate/actor 边界不当造成的设计缺陷本身,但这只是一个例子。
Item 是否有 Warehouse 不关心的任何信息(例如描述)?
如果答案是否定的,那么我将只将 Item 视为关联仓库位置的子项(即反转关系的方向)。只要仓库从不为 Item 提供 ActorRef,您就可以确定只有它可以向 Item actor 发送消息(Akka Typed 让您做出这种静态保证)。
如果答案是肯定的,我建议在仓库库存的上下文中,一个项目恰好包含该上下文中所需的信息,例如,目录描述之类的内容是不同上下文的责任(很可能是一项不同的服务)并且如果目录描述上下文需要了解有关库存的某些信息(例如它是否在任何地方 in-stock),那么它应该利用仓库库存发出的域事件。
我在演员模型中挣扎。让我用简单的例子。系统中有两种 actor 类型:Warehouse 和 Item。项目总是分配给特定的仓库。 AddStock 命令允许增加分配给给定仓库位置的库存数量。只有仓库知道自己的位置,因此 Item 必须询问其仓库该位置是否有效才能执行自己的业务逻辑。我想到了一些解决方案
- 命令 AddStock 包含仓库分片区域的 ActorRef,它允许 Item 向仓库询问位置。
- 以某种方式仅允许仓库发出命令 AddStock,该命令允许预先验证位置。不确定如何实现这一点,我考虑过私有命令或一些识别过程
我都不喜欢这两种解决方案。它给简单的任务增加了许多不必要的复杂性。我认为这可能是 OOP 思想的问题,分布式 actor 世界受其自身规则的约束。
在我的场景中,我将 Item 和 Warehouse 视为单独的聚合。它们都被实现为 Persistent Actor(使用 Cluster Sharding)。
只要您假设只有 Warehouse 可以调用 Item::AddStock,一切都很容易。然后 Warehouse 只是在调用之前验证位置。但是可以直接调用 Item 并跳过所有验证。 Item 无法知道调用的仓库是否正确。纯 OOP/DDD 方法很容易实现。项目知道仓库 ID 并且更改数量看起来像这样
item.addStock("L2", 100, warehouse)
知道仓库 id 的项目可以验证所提供的仓库是否为仓库。有仓库可能会询问位置是否有效。我当前的项目处理程序实现:
case AddStock(region, location, quantity) => {
region ? EntityEnvelope(warehouseId, HasLocation(location)) map (
_ => VerifiedAddStock(quantity)
) pipeTo self
VerifiedAddStock 是 Item 的私有对象,所以我确定谁是命令发布者(几乎是因为它不强制执行身份)。
所以问题是如何在 Actor 世界中建模这种关系?绕过分片区域 ref 是规范吗?
有人可能会认为这是由于 aggregate/actor 边界不当造成的设计缺陷本身,但这只是一个例子。
Item 是否有 Warehouse 不关心的任何信息(例如描述)?
如果答案是否定的,那么我将只将 Item 视为关联仓库位置的子项(即反转关系的方向)。只要仓库从不为 Item 提供 ActorRef,您就可以确定只有它可以向 Item actor 发送消息(Akka Typed 让您做出这种静态保证)。
如果答案是肯定的,我建议在仓库库存的上下文中,一个项目恰好包含该上下文中所需的信息,例如,目录描述之类的内容是不同上下文的责任(很可能是一项不同的服务)并且如果目录描述上下文需要了解有关库存的某些信息(例如它是否在任何地方 in-stock),那么它应该利用仓库库存发出的域事件。