首页 > 解决方案 > 如何使用事件源(轴突框架)处理从传奇中的 REST-API 传递的多个实体?

问题描述

所以目前我正在使用事件溯源和 CQRS 实现一个带有轴突框架的传奇。

情况如下:

我有 3 个微服务,m1、m2 和 m3

用户在 GUI 中输入 3 个实体 e1、e2、e3 的数据,这些数据分别由 m1、m2、m3 处理和持久化,因此 m1->e1,m2->e2,m3->e3

现在到传奇的必要性:

没有e2就不能存在e1,没有e3就不能存在e2。

因此,所有 3 个实体都必须由各自的服务成功创建,如果一个失败,saga 需要执行补偿事务以确保一致性。首先 m1 创建 e1,发出一个 e1CreatedEvent 并且一个协调器发送一个 createE2Command 作为对它的反应等等。

现在我的问题:

如何获取/存储用户输入的信息?在单个 RequestBody 中?那我该怎么处理这些数据呢?因为它需要以某种方式缓存才能与命令一起发送。

例如 m1 创建一个 createE1Command 并将来自 e1 的信息添加到它,然后在它成功创建后,编排器将启动一个 createE2Command 并在发送之前将 e2 的信息添加到该命令中......为此, e2 的信息需要以某种方式存储,直到需要它为止。

示例代码:

@Saga
public class ManagementSaga{

@Autowired
private transient CommandGateway commandGateway

@StartSaga
@SagaEventhandler
public void handle (e1CreatedEvent e1CreatedEvent){


  commandGateway.send (new CreateE2Command (e1CreatedEvent.Id, **HERE NEEDS TO BE THE INFO THAT THE USER CREATED PREVIOUSLY**)}}

我是否只是创建一个包含这三个实体信息的对象?这感觉真的不对。

现在我明白了,选择这样一个领域模型可能真的很糟糕,如果可能的话应该避免它,但这是为了科学:-)

标签: javacqrsevent-sourcingsagaaxon

解决方案


在这种情况下,我的第一反应是完全质疑设计。(微)服务似乎是围绕实体设计的。这种类型的设计可能在某些情况下有效,但在其他情况下不可避免地会导致分布式单体。您面临的挑战暗示了后者。

从 API 的角度来看,交互和系统的设计方式似乎也存在不匹配。虽然没有按照定义错误,但这也可能表明 API 不正确(不能正确反映系统的行为),或者行为模型不正确。

无论如何,为了给您一个希望比“它取决于”更有用的答案,您可以在多个命令甚至查询中获得单个交互结果。在所有情况下,它都不需要 Saga。

使用有关 E1、E2 和 E3 的信息进行单个请求。然后在您的控制器中,发送命令以创建 E3,根据该命令的结果创建 E2,最后创建 E1。没有信息需要“缓存”。请求信息在整个过程中都是可用的。然而,这种方法不是事务性的。如果服务崩溃,它可能会使进程半执行。

另一种方法是使用一个命令处理程序来注册用户的原始意图。那不是要创建 E1、E2 或 E3,而是要包含所有三者。进程生成的事件会触发 Saga 单独执行每个步骤,使用这些步骤中的事件来触发下一步。这个过程是事务性的,具有最终一致性特征。

我希望这有点道理。但是,我会认真重新考虑服务的模型/设计,让他们更多地关注流程(步骤),而不是实体(状态)。我见过太多的微服务项目因为以实体为中心的设计而失败......


推荐阅读