我最近正努力解决这个问题。
单服务器场景
您的客户端偶尔会连接到单个服务器。
我最近又在skillsmatter.com上看了greg youngs关于偶尔连接的系统的视频。
在那里,他说最好的方法是:
- 您有一个使用事件流的客户端
- 客户端将其已执行的所有命令保留在队列中
- 当服务器再次可用时,客户端将推送所有命令并再次下载生成的事件(在本地,客户端删除本地发出的事件,因为服务器是真相的唯一来源)
现在一切都好了,但我有一个更复杂的场景——一个有两个服务器的场景:测试和生产
mutli服务器secnario
- 因此客户端用于创建某种模板
- 然后它连接到测试服务器并推送它的命令=>我们在测试服务器上有了一个新的模板版本
- 客户端不时重新连接到测试服务器并更改模板
- 然而,在某一点上,该tempalte将被发布到生产服务器
您也可以将其视为git合并场景,在该场景中,您希望将所有更改从分叉的远程存储库a推送到原始远程存储库B。
问题是:
- 一旦客户端将其更改推送到测试环境,命令就会消失——那么它如何将任何更改推送到生产环境
- 此外:另一个用户可能会被用来实际将新模板发布到Production。(例如,因为发布是由it人员而非开发人员完成的)
所以我想这个问题基本上有两种解决方案:a)持久化命令流并将其下载到客户端,但这与事件源系统中只存储事件的事实相冲突b) 具有从已提交的事件中重新创建命令的机制。这样,客户端可以查看Production上的模板版本,以查看哪些事件尚未在那里发出。然后它相应地创建命令并执行它们。
我的问题:
- 我想这里只有b是可行的选择
- 选项b是否违反了事件来源和/或cqr的任何规则/原则
- 还有其他更好的方法吗
谢谢大家的想法!
更新
感谢您分享您的想法。但我似乎必须澄清一些事情——关于测试和生产的事情。
让我们假设我们正在构建一些应用程序框架,如salesforce:您可以通过点击来定义您的应用程序及其实体和工作流等。当然,您可以在单独的沙箱环境中执行此操作。当您完成第一个应用程序版本时,您将希望将其转移到生产服务器,这样您的用户就可以实际使用您"构建"的应用程序。
现在考虑以下几点:在生产中,你意识到有一个小错误,你马上就纠正了。然后您希望将这些更改转移回测试环境。
所以现在的问题是:真相的来源到底是什么?
正如大多数开发者所知,我喜欢把它编译成git。基本上我可以看到我有两个选择:
- git-rebase
其中一个环境是记录本。因此,在这种情况下,我必须收集所有命令,一旦我更新了生产,我就会推送这些命令。这就像git rebase
- git merge
让我们假设这两个系统都是"记录本"。在这种情况下,我需要同步测试环境中发生的事件和生产环境中发生发生的事件(因此我在测试和生产中得到了完全相同的应用程序定义)因此,Test中的事件不仅被附加到生产的事件流中,而且按照实际发生的顺序在生产事件流中进行排序。这就像数字合并
我个人更喜欢git merge选项,因为它会在两个系统中产生完全相同的事件顺序。当然,这将允许本地连接的客户端使用相同的方法进行分布式协作:假设我们在测试中定义并使用此事件源方法发布到生产的应用程序随后被多个偶尔连接的客户端用于实际收集数据。现在,多个客户端可以在彼此和服务器之间的相同聚合根同步上协同工作(就像在peer2peer系统中一样),同时仍然保持相同的事件流顺序。
然而,问题可能是客户端将事件e1同步到服务器,但该事件对应的聚合器ot已经处理了稍后发生的事件e2。因此,事件处理将不正常。
所以我的问题是:这种"git合并"有什么显著的缺点吗?
我认为你对记录/真相的定义让你陷入了困境。
如果生产是记录本,那么应该在那里发送命令。在这种情况下,测试实例在几个方面与客户端实例相似;它变成了一个沙盒,在那里你可以尝试一些东西,但它实际上可能并不代表";真理;当要把事情推进到下一个阶段时。因此,您可以将命令排队,并最终将这些命令传递到生产实例。
如果测试是这些更改的记录,那么您不是在与生产共享命令,而是在共享事件(或者可能是预测,取决于哪个模型更适合您的实际用例)。这在某种程度上类似于使用微服务:test是支持发送给它的命令的微服务,而production是一个单独的微服务对test中的事件做出反应——换句话说,production取决于测试中的读取模型。
乌迪·达汉对服务的评论可能有助于澄清
服务是特定业务能力的技术权威。任何数据或规则都只能由一个服务拥有。
我的猜测,基于你对"测试";以及";生产";,生产系统无权更改要进行测试的数据;它只是消耗一个数据视图。这使您直接回到单个服务器(实际上是:单个记录簿)的用例中。