1

我最近正在努力解决这个问题。

单服务器场景

您有一个偶尔连接到单个服务器的客户端。

我最近再次在 Skillsmatter.com 上观看了关于偶尔连接系统的 greg youngs 视频

他在那里指出,处理它的最佳方法是:

  • 您有一个使用事件流的客户端。
  • 客户端将其已执行的所有命令保存在队列中
  • 当服务器再次可用时,客户端推送所有命令并再次下载结果事件(在本地,客户端删除本地发出的事件,因为服务器是唯一的事实来源

现在这一切都很好,但我有一个更复杂的场景 - 一个有两台服务器:测试和生产

多服务器服务

  • 所以客户端用于创建某种模板
  • 然后它连接到测试服务器并推送它的命令 => 我们在测试服务器上有一个新的模板版本
  • 客户端有时会重新连接到测试服务器并更改模板
  • 然而,在某一时刻,该模板将被发布到生产服务器。

您也可以将其视为 git 合并场景,您希望将所有更改从分叉的远程存储库 A 推送到原始远程存储库 B。

问题是:

  1. 一旦客户端将其更改推送到测试环境,命令就消失了 - 那么它如何将任何更改推送到生产环境......
  2. 另外:可能会使用另一个用户将新模板实际发布到生产环境。(例如,因为发布是由 IT 人员而不是开发人员完成的)

所以我猜这个问题基本上有两种解决方案: a)保持命令流并将其下载到客户端 - 但这与在事件溯源系统中仅存储事件的事实相冲突b)有一种机制从已经提交的事件中重新创建命令。这样,客户端可以查看 Production 上的模板版本,以查看尚未在那里发出哪些事件。然后它相应地创建命令并执行它们。

我的问题:

  1. 我想这里只有 b 是一个可行的选择?
  2. 选项 b 是否违反事件溯源和/或 cqrs 的任何规则/原则?
  3. 有没有其他甚至更好的方法来做到这一点?

谢谢你们的想法!



更新

感谢您分享您的想法。但似乎我必须澄清一些事情 - 测试和生产的事情。

让我们假设我们正在构建一些应用程序框架,如 salesforce:您可以 - 通过使用点击 - 定义您的应用程序及其实体和工作流等。当然,您可以在单独的沙盒环境中执行此操作。当您完成第一个应用程序版本时,您将希望将其移至生产服务器,以便您的用户可以实际使用您“构建”的应用程序。

现在考虑以下几点:在生产中,您意识到存在一个小错误,并且您立即修复它。然后,您希望将这些更改传输回测试环境。

所以现在的问题是:真相的来源到底是什么?

正如大多数开发人员所知,我喜欢将其与 git 进行比较。基本上我可以看到我有两个选择:

  1. git rebase

其中一种环境是记录簿。所以在这种情况下,我必须收集所有命令,一旦我更新生产,我就会推送命令。这就像一个git rebase

  1. git 合并

让我们假设这两个系统都是“记录簿”。在这种情况下,我需要同步测试环境中发生的事件和生产环境中发生的事件(所以我在测试和生产中得到了完全相同的应用程序定义)所以来自测试的事件不只是附加到事件流中生产,但按实际发生的顺序在生产事件流中排序。这就像一个git 合并

我个人更喜欢git merge选项,因为它导致两个系统中的事件顺序完全相同。当然,这将允许偶尔连接的客户端使用相同的方法进行分布式协作:假设我们在测试中定义并使用此事件源方法发布到生产环境的应用程序随后被多个偶尔连接的客户端用于实际收集数据. 现在,多个客户端可以在相同的聚合根同步上一起工作,彼此和服务器(就像在 peer2peer 系统中一样),同时仍然保持相同的事件流顺序。

但是,问题可能是客户端将事件 e1 同步到服务器,但该事件对应的聚合根已经处理了稍后发生的事件 e2。所以事件处理会出现问题。

所以我的问题是:这个“git merge”有什么明显的缺点吗?

4

1 回答 1

1

我认为您对记录/真相的定义使您陷入困境。

如果生产是记录簿,那么这就是应该发送命令的地方。在这种情况下,测试实例在几个方面与客户端实例相似;它变成了一个沙盒,您可以在其中尝试事物,但在将事物推向下一阶段时,它实际上可能并不代表“真相”。因此,您将命令排入队列,并最终将这些命令交付给您的生产实例。

如果测试是这些更改的记录簿,那么您不是在与生产共享命令,而是在共享事件(或者可能是预测,取决于哪个模型更适合您的实际用例)。这有点类似于使用微服务:测试是支持发送给它的命令的微服务,而生产是一个单独的微服务,它对来自测试的事件做出反应——换句话说,生产依赖于测试中的读取模型。

回顾 Udi Dahan 对服务的看法可能有助于澄清事情

服务是特定业务能力的技术权威。任何一条数据或规则必须由一个服务拥有。

根据您对“测试”和“生产”的使用,我的猜测是生产系统无权更改被推送测试的数据;它只是使用该数据的视图。这让您完全回到单个服务器(实际上:单个记录簿)用例。

于 2016-12-23T15:54:32.183 回答