根据依赖关系查找聚合ID

时间:2019-04-18 06:07:22

标签: domain-driven-design axon

我有一个非常混乱的问题,因为我不确定这是否更多涉及全球设计问题。

我提供的服务定义了一些汇总,这些汇总发布了事件。让我们从服务中选择一个集合,并将其称为A。 现在,我定义了另一个具有应该与A一起使用的聚合的服务,我们将第二个聚合称为B。

当A发布某个事件时,我想向B发送命令(最好是通过传奇),但是我很难计算B的适当ID(A不知道B存在,因此它发布的事件没有关于如何计算ID的任何提示)

我可以想到几种可能的情况:

第一个方法是根据A的ID静态计算B的ID,例如在轴突中,我可以做类似some-id-${suffix}的事情,因此当我用some-id从A接收事件时,我可以立即知道应该将其发送到some-id-B

第二个会使用读取端吗? (我不确定该如何正确调用)并查询该事物,然后尝试根据A id查找B id,但这似乎有些过分。

有什么我能读懂的内容,可以引导我了解各种可能的情况,并提示我如何处理它们?谢谢!

1 个答案:

答案 0 :(得分:2)

据我了解,您具有从集合B到集合A的关系。这种关系是正常的,并且始终存在。

注意:由于这个问题很笼统,没有上下文,因此我可能会遗漏一些东西。如果有比上述情况更特殊的情况,请通知我。

This is a great read for aggregate design

注意:请阅读Martin Fowler的this video,然后再阅读本答案的其余部分,我强烈建议这样做,因为它详细解释了与事件和命令有关的概念。

注意:由于实体一词也很重要,因此从现在开始,我将不再使用聚合,因此假设每个实体(玩家用户游戏)是其自身集合的根,并且是一致性边界,因此在这种情况下,将使用域事件的最终一致性。此刻我也将忽略CQRS,以避免不得不谈论读取侧和写入侧。我们将讨论并实现模型

让我们以游戏为例。您有一个播放器,该播放器应代表游戏中的用户玩家实体应以某种方式引用游戏用户。它可以通过直接引用或通过ID。在分布式系统的情况下,将通过ID。对于我们的示例,让我们为ID使用UUID(例如 8d670541-aa51-470b-9e72-1d9227669d0c ),以便我们无需定义架构即可随机生成它们,自动生成序列号(例如在SQL数据库中) )或特殊算法。 假设一个用户具有 UserStatistics 。因此,当玩家得分(例如通过杀死射击游戏中的其他玩家)时,应创建 UserStatistics 实体(如果不存在)并进行更新。 UserStatistics 还应通过ID引用 User ,因此我们具有从 UserStatistics User 的依赖性。

UserStatistics 如下所示:

UserStatistics {
  UUID UserID,
  uint KillsCount,
  uint GamesPlayedCount
}

由于没有用户播放器将不存在,因此应先创建用户。因为 Player Game 的一部分,所以意味着 Game 应该首先创建。让我们用无所不在的语言定义一些术语。 用户 “加入” ,通过成为其中的 Player 游戏。可以说,游戏将由其他人而不是用户创建,以避免讨论用户创建游戏并同时加入游戏时的情况,等等。 。如果在同一笔交易中发生这种情况,则... 游戏将类似于MMO,由某人创建,并且普通用户可以加入。

用户 加入一个游戏时,将使用创建玩家实体userID gameID 。创建没有用户ID 游戏ID 玩家是无效的。

让我们与命令事件讨论问题。 命令可以通过事件进行触发。让我们使用观察者模式。一个实体必须观察另一个实体的事件。在我们的示例中,这意味着依赖性从 UserStatistics (观察者)到 User Player (主题/消息生产者)。在 UserStatistics 上执行特定 Command 的事实是对 Player 中引发的 Event 的反应。 用户不应以任何方式影响播放器播放器。通过使用 Event 故意以被动积极的方式触发特殊的 Command 并不是一个很好的策略。 命令可以由事件触发,但是触发不仅只能是一个特定的命令。可以触发许多不同的命令,只有相关的实体服务系统应该关心发生的情况。 播放器用户仅提供事件

用户加入游戏并创建玩家时,它将通过ID引用两个实体,因此看起来像这样:

Player {
  UUID GameID,
  UUID UserID
}

还将 UserJoinedGameEvent 事件从 User 实体引发(它可能是从 Game 引发的,但我们将选择 User )。看起来像这样:

UserJoinedGameEvent {
  UUID GameID,
  UUID UserID,
  UUID PlayerID
}

UserStatisticsService 可以订阅事件并更新统计信息。

用户加入游戏时,将开始收集统计信息的过程,我们将更新(或创建不存在的)他的 UserStatistics 他玩过多少场比赛。在玩家被杀的同时,我们将不得不再次更新统计信息。

StartGatheringUserStatisticsCommand 将由 UserJoinedGameEvent 事件触发。

让我们添加一个如下所示的事件 PlayerMadeKillEvent

PlayerMadeKillEvent {
 UUID UserID,
 UUID PlayerID,
 UUID GameID
}

UserStatisticsService 将订阅 PlayerMadeKillEvents ,并通过使用 PlayerMadeKillEvent.UserID 查找 UserStatistics 特定的用户

用户退出游戏时,可以引发 UserQuitsGameEvent ,并且统计信息收集可以停止。

在此示例中,我们没有用于生成特殊ID的特定架构,我们可以引用将首先创建的其他聚合,然后使用其ID。