在我的CQRS/ES设计中,我有一个时间上的例子。为了便于讨论,让我们以微软的示例为基础,讨论这个主题,即会议管理(https://msdn.microsoft.com/en-us/library/jj554200.aspx)。
两种情况:会议管理和订单管理。在会议管理中,您创建会议并更改其属性(例如:最大席位)。会议管理通过事件总线与订单管理进行通信。这样,订单管理就可以知道何时创建新会议,并在其上下文中实例化跟踪对象(座位可用性)。诸如“最大座位可用性从100降低到80”这样的事件也是通过事件总线从conf传递到命令mgmt。
这是第一个案子。
第二种情况是:
这些问题源于技术问题(事件传输中的延迟)。是否有一种纯粹的技术方法来避免?如果不是的话,业务方式/设计方法将如何克服呢?
补充注意:我知道这是与CQRS/ES体系结构相关的最终一致性问题。在单个上下文中,这可能更容易处理,因为您可以为此使用命令(例如: undo)。但是,在不应该传递命令的有界上下文之间,您只与事件通信,我认为事件不是正确的抽象(因为它代表发生的事情)。还是我漏掉了什么?
补充注意:也许本文可以提供更多的上下文和解决方案的提示,但是对于这个问题中的具体情况,我不这么认为(这不是关于无序消息)。http://blog.jonathanoliver.com/cqrs-sagas-with-event-sourcing-part-i-of-ii/
添加注意:或者.,在订单管理上下文中,我们可以简单地排队命令购买一个座位,直到我们知道我们已经从会议管理上下文中收到了最新的/最后的事件。我是说,这些事件都有时间戳,对吧?因此,我们可以将从context上下文中收到的最后一个事件的时间戳与购买座位的命令的时间戳进行比较。如果最后一个事件的ts小于命令的ts,则只需推迟命令的执行,直到接收到比命令的ts大的事件为止。这类事情将是过程经理(saga)的责任。
那能行吗?这是正确的做法吗?
添加注意:相关线程> 在CQRS http应用程序中实现Saga/Process。我想我们和流程经理走在正确的轨道上了。正如回答者说的:“您根本不立即回答”已确认的订单“。看看Amazon和其他购物网站是如何做到的:在订单提交时,您只收到”订单接受确认(例如,HTTP代码202已被接受)“。
这取决于您的流程管理器的逻辑来决定何时实际执行命令(基于特定条件、内部状态,或者在本例中是来自另一个上下文的最新接收事件)。
有什么意见吗?
谢谢,拉卡
发布于 2016-09-06 14:40:47
三种可能性
首先,你接受最终的一致性。正如注释中所指出的,在许多最终的一致性场景中,如果能迅速意识到这一问题,企业将有办法缓解这个问题--因此,您需要一些东西来监视您的模型中出现的事件,注意到您保留的座位数量与售出的座位数之间存在差异,并且可能需要一个基于任务的UI,以便让人做正确的事情。
其次,检查业务,看看您是否真正正确地建模了真正的业务流程。例如,您可能在购买座位时遗漏了几个阶段;订单管理部门可能需要在确认订单之前预订座位。
(也就是说,说一个顾客想要20个座位的活动可能是一个独立的事件,它说我们实际上把它们卖给了她,两者都不同于会议管理部门为该客户保留座位的事件)。
请注意,这实际上并不能使您免于商业问题--在想要购买20个座位的客户和想要缩小观众规模的会议组织者之间,您仍然有一个竞争条件。你得到的是一个稍微清晰的失败模式(如果客户赢得了争夺席位的竞赛,那么会议管理部门就可以拒绝减少会议次数)。同样,如果主办方赢得比赛,预定座位的尝试也将被拒绝)。
这假定会议管理部门应保持一个不变的不变,即保留席位的数目少于分配的数目。这在你的生意中可能并不是真的。此外,能够跟踪客户试图预订的座位超过可用位置的次数,对企业可能是有用的。
第三,您的服务边界可能是在错误的地方绘制的。Udi Dahan
任何数据或规则必须由一个服务拥有。
如果会议管理中的席位和顺序管理中的席位是相同的,那么它们可能属于(相同的服务边界)。
我的建议是,在有需要时,自动化应该能够避开领域专家的视线,我的建议是,你应该主要考虑第一种方法--你能把它的控制权交给商业专家吗?如果你做得对,你很可能会有一个成功的项目。
发布于 2016-09-06 20:05:40
正如我的评论和这里的另一个答案所提到的,您应该首先与业务检查在此场景中发生的情况。通常情况下,如果你向企业提出这个问题,事情就简单多了。
处理这些问题的通常方法是采取某种补偿行动。例如,如果你要在一个标准的电子商务网站上下订单,但是当它被处理的时候,货物是缺货的,你通常会收到补偿措施--一封电子邮件,上面写着它缺货,或者是一个替代物品的报价等等。
在你的例子中,如果有人订购了20个座位,但后来又减少到15个,你可以:
它们就在我头顶上.
重要的是要问企业。他们经常会给你惊喜!
如果这个答案回到永远都不可能发生的地步,那么另一个答案对此有一些明智的建议。
发布于 2016-09-07 06:46:55
让我们开始,我认为,在您的设计最大的问题:您的聚合需要很长时间来更新。
设计您的产品的一种很好的方法是这样的: GUI -> API API ->命令-> CommandHandlerTell聚合可以更新->事件首先是聚合,然后是其他订阅者。您还需要确保在处理新命令之前应用事件。因此,在开始新命令之前,CommandHandler应该完成对命令的处理。现在,考虑到您希望为任何给定的时间单位处理多少命令,您将不得不对其进行建模。但是,如果这样做,则确保聚合能够做出适当的决定,如果命令是有效的还是无效的。
为什么我认为这是个大问题?因为如果你有一个命令想要预订所有的座位,你要确保有那么多的座位可用。你不希望一个落后的事件减少可用的座位数量。总结性必须有真实的信息,永远。否则,您将创建无效事件,这是一个大的不-不。
所有这些都提出了一个问题:“业务逻辑应该在哪里?”嗯,这可能有点棘手。聚合是唯一(或者应该是唯一)知道它在哪一个状态的人。但是CommandHandler也应该检查命令是否有效。这样,您的逻辑就可以在聚合和commandHandler之间分裂。进行拆分的一个简单方法是,CommandHandler应该只检查它是否是一个有效的命令,而聚合应该检查‘我真的能这样做吗?’。
所以,如果我们想象上面提到的分裂,我们有你的场景1。
这样你就可以确保在座位都订满的时候不能减少座位的数量。但既然你必须能够真正改变它们,就像我们(愚蠢的)现实中的情况一样。火灾,你将不得不为这做一些机制。就我个人而言,我可能会为此做一个新的Command+Event,这涉及到对客户的一些回报和一些道歉。
我希望这对你有所帮助。
https://stackoverflow.com/questions/39334288
复制相似问题