活动来源-“升级”投影仪

时间:2018-09-19 00:13:42

标签: architecture cqrs event-sourcing

我最近开始从事一个使用CQRS / ES作为基础体系结构的项目,但是我遇到了一些麻烦,但是我找不到关于如何解决此特定问题的任何可靠信息。

基本上,我想做的是处理这样的情况:我需要在以后的某个特定时间点处理其他事件类型,例如当系统的特定视图需要来自不同类型事件的数据时。

很显然,这将需要再次处理整个事件(或从某个检查点),但是要在新的投影中包括其他事件。

我的问题是,人们通常如何解决这个问题?据我了解,这可能是在当前预测的基础上开始新的预测,然后将旧的预测取而代之的情况。

尽管这引起了一些其他问题:

  1. 如果要投影到关系模型中,如何优雅地处理升级,鉴于两个投影都将使用不同的表(也许甚至在不同的数据库上。)
  2. 此时可以完全丢弃旧投影机吗?还是将旧投影机的配置悬挂在某个地方的存储中完全合理吗? (我想不出您需要创建较旧的投影的原因)

任何指针都很棒:)

3 个答案:

答案 0 :(得分:1)

格雷格·杨(Greg Young)的建议是在生产中将投影功能视为不可变的。

表示如果需要其他读取模型,则只需创建一个新模型(从零时开始),而在不需要旧模型时,则将其删除。

是的,这可能需要一些时间和额外的存储空间,但是如今这并不是什么大问题。

答案 1 :(得分:1)

您有两个问题。让我们将其分为两部分:

  • 关于关系模型的编写位置。
  • 关于放弃旧的预测。

您需要分析的第一件事是,您是否控制读者,以及是否与整个项目一起部署?

通常对于小型项目,您只需要编写代码或几十个编码器,就适用。相反,如果公司中有成百上千的编码员,并且您不知道到底是谁在阅读您的预测,那么您最好为队友设计一个“沟通计划”,以使旧的预测在计划的日历中过时。 >

假设您处在复杂的情况中。

a。设计新表

为新的投影机设计新表,例如,如果您的表是MonitorsMousesKeyboardsAudioDevices,则可能现在要创建{{1 }},Monitors_v2Mouses_v2Keyboards_v2或它代表贵公司的任何有意义的名称/干净编码的名称(例如Audiodevices_v2

如果您的显示器有所变化,但您的键盘没有变化,我建议您也制作一组完全分开的表,其中包含所有汇总和相关概念,以避免与旧事物进行任何交互。如果您有MonitorsWithManufacturerInformationKeyboards_v2具有重复数据,那么没人会抱怨。如果您将它们强制设置在同一张表中,那么您将被这些交互杀死。

b。编码新的投影机

我通常在投影机内部具有放置和创建自己的桌子的能力。例如,我所有的投影机都实现了Keyboard界面强制执行的resetState()方法,通常它只是拖放并创建一些表:

Projector

然后将功能添加到投影机中进行处理:

  • 一个事件
  • 以及所有未决事件

所有待处理事件将意味着读取指针的位置,从指针读取所有事件到当前状态,并按顺序处理每个事件,然后更新指针,以便后续处理所有待处理事件的调用是幂等

c。部署并运行

部署新代码(如果有的话,进行预生产)并运行:

  • 重置状态
  • 处理所有事件

即使您没有预生产并且在生产中运行它,这也是安全的,因为没人知道新表的存在。没有消费者从那里阅读。

d。重复编码和部署

检查突起是否具有所需的形状。如果它们不具有所需的外观,则可以安全地编辑这些投影仪,然后从零开始重新运行它们:销毁表,重新创建它们并存储投影的数据(当前状态的缓存)

重新检查等等,直到获得满意的结果。

e。连接到实时流

一旦进行了最初的赶超,请确保您的放映机收听广播,并更新放映时间,这是一个新事件。

对于此答案来说,无论是写触发,时钟触发还是读取触发都没有关系,无论您是逐个事件还是分批处理流事件都无关紧要,只需确保在初始“重置”之后,流开始获取缓存。

f。与让读者交流的队友交流

一旦准备就绪,就可以在那些新的关系表中安全地与负责编码已经部署了新缓存的读者的队友进行沟通。

g。向后兼容性:是或否?

请勿删除旧版本,除非您能从所有读者那里获得他们已成功升级到新版本的反馈。

如果您不确定(例如:确定为99.999999999%),请不要删除旧版本。

如果您确定(例如:确定为100.000000%)断开投影机的某些产品周期(取决于您的项目,可能是数分钟,数天或数周),并且没有人抱怨抱怨读取不良数据(仔细检查)。

如果有人抱怨:这很容易,请运行旧的投影机以赶上最近发生的事件并重新连接它们。等到读者说“我已更新到v2”并重复。

如果没有人抱怨,您可以删除数据库表(它们不需要需要任何类型的备份,因为它们都是过去在采购事件中创建的),还可以删除旧的投影仪的代码来清理您的代码库(如果您需要了解有关旧投影的制作方法,这就是为什么您拥有git或类似的东西)。

如果您在旧的投影数据中存在“错误”,则没有软件可以使您免于与所有队友友好交流,除非他们同意处理不正确的数据(否则可能会发生错误不会影响阅读器,并且该代码可以解决旧版本的问题。

如果您是唯一的编码器,或者与20人以下的小团队一起工作,则很容易控制关机。但是我建议即使您是一个小团队,也要坚持这种“放下之前加倍”。

所以要回顾一下:简明的答案

您的问题#1:如果要投影到关系模型中,如何优雅地处理升级,鉴于两种预测都将是可能的,我将如何尽可能无缝地处理转换使用不同的表(甚至可能在不同的数据库上)。

  • 花点时间选择新表的干净代码名称,并确保新的投影机永远不会触碰旧的输出,因为名称不会冲突。迭代直到新厨师准备好。当闻起来很香时,将其服务于消费者。消费者的任务是按照自己的节奏进行切换。

您的问题2:这时可以将旧投影完全丢弃吗,还是将旧投影的配置悬挂在某个地方的存储区中完全合理? (我想不出您需要创建较旧的投影的原因)

  • 除非您100%确保没有读者闲逛,否则您无法删除数据或代码。如果没有读者,您可以暂时不给它喂食,以提高最后一刻的意识(这个词存在吗?)。经过一段安全的时间,没有任何抱怨,您可以安全地删除数据而无需备份,因为事实上,数据是事件的“功能”。只要您有代码的版本控制系统支持,您也可以安全地删除旧投影机的代码。

希望有帮助!

答案 2 :(得分:0)

鉴于您已按顺序对事件存储中的所有事件进行排序。

一方面,您拥有当前的视图模型,该模型与事件存储是最新的,并且可以继续投影新事件。

另一方面,正如您所说,您开始将事件存储中的所有事件投影到新的视图模型上。

在某些时候,两个视图模型都将赶上事件存储,因此它们都代表了数据的当前状态。那一刻,您可以将查询指向新的视图模型(并且可能会忘记旧的视图模型)。