Domain driven design 如何控制事件驱动体系结构中消息的幂等性?

Domain driven design 如何控制事件驱动体系结构中消息的幂等性?,domain-driven-design,amazon-dynamodb-streams,event-driven-design,Domain Driven Design,Amazon Dynamodb Streams,Event Driven Design,我正在从事一个项目,其中DynamoDB被用作数据库,应用程序的每个用例都由在数据库中创建/更新项目后发布的消息触发。目前,该准则遵循以下方法: repository.save(entity); messagePublisher.publish(event); Udi Dahan有一段视频,名为《无分布式事务的可靠消息传递》,他在视频中谈到了一种解决方案,解决了系统在保存到DB之后,但在发布消息之前,由于消息不是事务的一部分而可能发生故障的情况。但在他的解决方案中,我认为他假设使用SQL数据库

我正在从事一个项目,其中
DynamoDB
被用作数据库,应用程序的每个用例都由在数据库中创建/更新项目后发布的
消息触发。目前,该准则遵循以下方法:

repository.save(entity);
messagePublisher.publish(event);
Udi Dahan有一段视频,名为《无分布式事务的可靠消息传递》
,他在视频中谈到了一种解决方案,解决了系统在保存到DB之后,但在发布消息之前,由于消息不是事务的一部分而可能发生故障的情况。但在他的解决方案中,我认为他假设使用
SQL
数据库,因为该过程涉及将正在处理的消息的correlationId、实体修改和要发布的消息保存为事务的一部分。使用
NoSQL
DB,我想不出一种干净的方法来存储有关消息的信息

解决方案是使用
DynamoDB
streams
,订阅使用
Lambda
或其他服务发布的事件,将其转换为特定于域的事件。我的问题是,我无法从域逻辑发送消息,逻辑将分布在处理消息的服务中,
Lambda/service
对更改作出反应,解决方案将是特定于平台的


有没有其他方法来处理这个问题?

我不能说基于DynamoDB的具体解决方案,因为我从未使用过这个引擎。但我已经在MongoDB上构建了一个事件驱动系统,所以我可以分享我的经验教训,您可能会发现对您的案例有用

您可以有不同的方法:

1) 基于事件源方法,您可以将用例生成的事件/消息保存在事务中。在Mongo中,当您只是向同一集合插入/附加新项时,可以确保原子性。无论如何,如果引擎不提供该功能,那么查询操作是如此集中,以至于您将错误的可能性降至最低

一旦存储了所有事件,您就可以使用它们并将它们投影到给定的状态,然后将更新后的状态保存到另一个事务中

在这里,您必须处理最终的一致性问题,因为在您预测事件之前,读取模型中的数据将过时

2) 另一种方法是应用
UnitOfWork
模式,在该模式中缓存所有查询操作(插入/更新/删除)以保存事件和状态。一旦用例完成,您将对数据库执行所有缓存查询(flush)。通过这种方式,尽管操作不是原子的,但您再次将它们集中到足够大的程度,以最小化错误

当然,如果需要ACID数据库,最好的方法是使用ACID数据库,而任何其他方法都是接近ACID数据库的一种变通方法


关于发布事件,我不知道您的意思是否是将它们发布到消息传递机制,如rabbitmq、Kafka等。但这必须是一个后台过程,您从DB获取事件并发布它们,以便在同一事务中中断2阶段提交

在第一个示例中,流程是:1)获取事件(新订单)并将其存储在存储中2)使用事件并更新读取状态(新订单(1))3)发布前一个已使用的事件(创建订单)。如果是这样,我如何处理从2)到3)的转换?DynamoDB为此提供了一个流,因此对文档的任何修改都会发布一个事件。但您必须以某种方式处理重试。如果我创建了一个文档,然后系统立即崩溃,则会重试该事件。即使该操作是幂等的,也会发布orderCreated/Update。鉴于这种方法,我理解任何前端都需要使用WebSocket之类的工具,以便能够等待一条消息,表明请求已成功处理。或者至少乐观一点,说邮件在回复中已被处理,但请倾听出现问题时可能收到的任何更新。