数据库中的 Axon CQRS 和 EventSourcing 深度验证

Axon CQRS & EventSourcing deep validation in the db

我正在将现有的 crud 应用程序迁移到 Axon,我对以下情况有些担忧。我有下面给出的 api 来创建组,

 @PostMapping
public Mono<IdDto> createGroup(@RequestBody @Valid CreateGroupCommand command) {
    log.trace("Create GroupResponseInfoDto request {}", command);
    return commandGateway.send(command)
            .map((o) -> new IdDto((UUID) o));
}

命令看起来像,

   @Data
public class CreateGroupCommand {

    @NotBlank
    private String name;

    @NotBlank
    private String description;
}

这里的主要要求是组名必须是唯一的。 因此,在聚合中我有以下代码来检查这个逻辑。

  @CommandHandler
public GroupAggregate(CreateGroupCommand command, GroupRepository groupRepository, ModelMapper mapper) {
    log.trace("Handle create group command {}", command);
    groupRepository.findByName(command.getName())
            .ifPresent((g) -> {
                throw new ApplicationException(UserMsError.GROUP_ALREADY_EXISTS.name());
            });
    GroupCreatedEvent event = mapper.map(command, GroupCreatedEvent.class);
    event.setId(UUID.randomUUID());
    AggregateLifecycle.apply(event);
}

一旦验证失败,事件就会被投影仪保存到数据库中。

@EventSourcingHandler
public void on(GroupCreatedEvent event) {
    log.trace("Group create event {}", event);
    groupRepository.findByName(event.getName())
            .ifPresent((g) -> {
                throw new ApplicationException(UserMsError.GROUP_ALREADY_EXISTS.name());
            });
    Group group = modelMapper.map(event, Group.class);
    groupRepository.save(group);
}

现在的问题是,在命令执行和事件结果持久化到组 table 之间有一些间隔时间。如果当时另一个用户创建了一个组,则该命令不会失败,因为数据库中不存在该记录。现在,我在 Axon 网站上看到有一种创建临时 table 的方法,我们将命令执行放入一些临时 table 中,我们可以将其用于验证目的,但这需要额外的编码和非常额外的每个这样的要求的努力。这也意味着,如果我们保留命令执行的详细信息,并且由于某种原因该过程失败,那么该记录将存在于我们的验证 table 但不存在于系统中。如果我们尝试验证事件执行的场景,可能不需要额外的努力,但在这种情况下,问题是我无法使 API 调用失败,以便用户知道结果。您能否推荐是否有其他方法无需中间检查即可验证输入?

您正在查看的问题是基于集合的验证。无论何时处理 CQRS,都需要额外的工作来验证集合。

虽然不确定,但我假设您是在谈论 Set-Based Consistency Validation blog? That is, for a reason, the suggested approach to deal with set validation. Note that the implementation used in the blog can be found here

已添加,最近看到更新不包含您描述的问题如下:

It also means, if we persist the details on command execution, and for some reason, the process fails, then the record will exist in our validation table but not on the system.

通过 UnitOfWork 支持的 Axon 事务逻辑将在出现故障时回滚整个事务。因此,您可以在 UnitOfWork 中执行任何操作,包括更新另一个 table 以进行验证。

我知道这是一些样板代码,但它是对集合具有唯一性要求的困境。 可能 是您可以研究的是通过聚合标识符强制唯一性。 Axon 的事件存储逻辑确保没有两个事件使用相同的聚合标识符。因此,如果您尝试为已经存在的聚合标识符输入一个新的聚合(因此是一个新事件),操作将失败。 但是,只要描述了基于集合的一致性验证问题,这种方法通常是不可行的,所以我猜它不会帮助你。

最后,我将从博客上的共享存储库中获取您的胜利,以尽量减少您在此事上的个人努力。