你好,我有以下场景,我不明白如何获得最终的一致性:
- 用户1使用基于任务的ui修改客户名
- App Service调用聚合 上的操作
- 总线使用nservicebus 发送消息
- NServicebus服务死亡
- 用户2获得聚合并呼叫更改地址
- 聚合操作称为
- 域事件触发
- 消息放到总线上
- 汽车重新启动
- 消息2先收到
- 消息2已处理,其他有界上下文更新为新地址
- 消息1现在接起,但顺序错误
- 现在发生了什么
在13中,如果我们在事件中传递聚合的版本,会有乐观并发错误吗?
如果是,Message 1 new被应用到另一个上下文中的对象。我们如何保持一致性?
这是阻止我在我的域中应用事件的问题。欢迎大家帮忙。
基本思想是更新另一个上下文中的另一个聚合。我只是被这个的并发性技术卡住了。
在命令处理程序和命令在总线上推送的意义上,我们不使用事件源或CQRS。这只是我们希望异步发生的事件处理,因为我们有一个现有的设计,我们不希望改变。
Blair
一般情况下,您将对消息进行排队。如果他们要排队,你会得到适当的排序。如果你想使用一些不支持servicebus排序的东西,那么给你的事件添加一个序列号,这样对方就可以正确地对它们重新排序。TCP自1981年以来一直这样做http://www.ietf.org/rfc/rfc793.txt:)
哎呀:我刚刚注意到您实际上在示例中使用了2个不同的任务(客户名称,然后客户地址)。当然,这将是一个没有问题,因为顺序应该真的不重要。但我将留下我的答案,以防你的意图是有两个相同类型的变化。
总是有几个问题/问题出现在脑海中:
一方面,您的示例不需要端点失败,因为2个用户可以同时更新地址,处理的顺序可以是随机的。所以问题就变成了哪一个是正确的地址。所以解析需要更多的分析。首先,我想我们可以假设客户不会频繁移动,以至于两个用户同时更新地址(甚至在它附近)——:)
尽管如此,也许第一个地址是正确的。
我认为对于这样的场景,您需要确定并发性,甚至一些其他容忍度是否是一个问题。因此,也许一个地址可能每天只更改一次,其他任何更改都需要其他交互作用。因此,一些异常处理将是一个选项。
你真的不应该把它降到技术层面去尝试解决它,而应该看看过程/业务含义。
对于一个简单的解决方案,我会将消息发送日期与特定类型的最后操作日期相匹配。因此,当处理消息时,对于ChangeAddressCommand
,您可以将其与当前的LastAddressChange
进行比较,如果消息是在最后更改日期之前发送的,则拒绝它。
这里讨论NServiceBus的类似问题。OP建议使用ibus . handleccurrentmessagelater()来旋转,直到另一个消息到达。这是可行的,但可能会有问题,因为你永远不知道你要等多久。
一个更复杂的选择是使用一个saga,它将等待所有指向特定版本的消息到达。在这种情况下,排序是基于版本完成的,并且只有当聚合版本中的所有更改都发布到另一个BC时才有可能。假设Message 1对聚合的版本2进行操作。然后,它增加聚合的版本,并发布一个事件,声明它已对版本2进行了操作。消息2对聚合的版本3进行操作,并发布一个事件,声明它已对版本3进行了操作。当另一个BC中的NServiceBus端点在消息1之前接收到消息2时,它知道最后接收到的消息对聚合的版本1进行了操作,因此它需要一个对版本2进行了操作的消息。它将开启一个等待下一个消息的传奇。一旦接收到消息1,传奇将应用消息1,然后应用消息2,并释放传奇状态。如果不能接受使用版本进行测序,可以使用另一种测序策略。
根据这个你应该问自己:
失败对业务的影响是什么?
在当前的情况下,每一百万个请求出现一次这个问题。如果您接受这两个请求都是有效的,我认为对业务不会有太大的影响。