事件采购:处理派生数据

时间:2016-01-19 16:45:05

标签: event-sourcing

事件采购系统如何处理派生数据?我在事件采购中阅读的所有示例都表明服务对事实事件的反应。一个流行的例子似乎是:

银行帐户系统

活动

  • 存入资金
  • 撤回资金

服务

  • 余额服务

然后,他们将展示Balance服务如何在任何时候从事件中获得状态(即余额)。那讲得通;那些事件都是事实。毫无疑问,他们发生了 - 他们是系统外部的。

但是,我们如何处理系统计算的数据?

E.g。

透支服务:

一项服务,负责监控余额并在低于零时执行某些操作。

事件采购方法是否规定了我们应该如何使用(或不使用)派生数据?即余额。也许下列之一?

1)使用:[资金撤回事件] + [余额服务查询]

收听“资金撤销”事件,然后向Balance服务询问当前余额。

2)使用:[余额更改事件]

获取余额服务以抛出包含当前余额的“余额已更改”事件。据推测,这不是一个“事实”,因为它不是系统的外部因素,因此容易被误算。

3)使用:[资金撤销事件] + [资金存入事件]

我们可以跳过Balance服务,让每项服务直接从事实中保持自己的平衡。 ......虽然这会导致每个服务都有自己的(可能不同的)余额版本。

2 个答案:

答案 0 :(得分:2)

活动采购是一门不断发展的学科,拥有一系列不同的实践,从业者和有魅力的人。您无法期望它们为您描述的所有场景提供一些非常一致的建模技术。这些场景中的每一个都有它的优点和缺点,你指定了其中的一些。此外,从一个项目到另一个项目,它可能会有很大差异,因为业务需求(市场的进化压力)会有所不同。

如果您正在开发一些任务关键型系统,并且希望始终保持非常一致的平衡 - 那么使用RDBMS和ACID事务会更好。

如果您需要最大速度并且您对最终一致状态感到满意并且不太担心您的余额的精确度(某些事件可能因此而在这里和那里丢失)那么您可以异步地从事件中获得对余额的预测

在这两种情况下,您都可以使用事件源,但您不必异步生成投影。如果您真的需要这样做,那么在您对写入模型进行更改的同一事务范围内生成投影是可以的。

这会让Greg Young高兴吗?我不知道,但如果有一天你的余额可能在任务关键型系统中不同步,谁会关心这些事情...

答案 1 :(得分:2)

  

负责监控余额并在低于零时执行某些操作的服务。

执行摘要:在事件源系统中处理这种情况的方式实际上并不与备选方案有所不同。

退一步 - 拥有域模型的优势是确保所有提议的更改都满足业务规则。借用CQRS语言:我们将命令消息发送到命令处理程序。处理程序加载模型的状态,并尝试应用该命令。如果允许该命令,则更新并保存对域模型状态的更改。

在持久化模型状态之后,命令处理程序可以查询该状态以确定它们是否是要执行的未完成操作。 Udi Dahan在他关于Reliable messaging的讨论中详细描述了这一点。

因此,描述服务的最直接方式是每次帐户余额更改时更新模型,并在余额为负时设置“帐户透支”标记。保存模型后,我们会安排与该状态相关的任何操作。

事件采购的部分理由是域模型的状态可以从历史中推导出来。也就是说,当我们试图确定模型是否允许命令时,我们加载历史记录,并从历史记录中计算当前状态,然后使用该状态来确定是否允许命令。

在实践中,这意味着我们可以在编写AccountDebited事件的同时编写AccountOverdrawn事件。

可以订阅AccountDebited事件 - Pub / Sub。典型的处理是新事件在成功写入记录簿后发布。订阅来自域模型的事件的事件侦听器会观察该事件,并调度要运行的命令。

离题:通常,我们希望至少一次执行这些活动。这意味着要跟踪确认。

因此,事件处理程序也是一个有状态的东西。它中没有任何 business 状态,当然也没有允许它拒绝事件的规则。它跟踪的是它所看到的事件以及需要安排的行动。加载此事件处理程序(通常称为进程管理器)的规则就像域模型的规则 - 从记录簿中加载事件以获取当前状态,然后查看正在处理的事件是否发生了任何变化。

所以它实际上订阅了两个事件 - AccountDebited事件,以及从活动返回的任何事件,以确认它已完成。

这个相同的机制可用于更新域模型以响应来自其他地方的事件。

示例:假设我们从ATM获得了一个FundsWithdrawn事件,我们需要更新帐户历史记录以匹配它。因此,我们的事件处理程序被加载,自行更新,并安排运行RecordATMWithdrawal命令。加载命令后,它会加载帐户,更新余额,并像以前一样写出AccountCredited和AccountOverdrawn事件。事件处理程序查看这些事件,根据元数据加载正确的状态进程状态,并更新进程的状态。

在CQRS术语中,这一切都发生在“写模型”中;这些过程都是关于更新记录簿的。

余额查询本身很简单 - 我们已经证明,余额可以从域模型的历史中得出,而这正是您的余额服务应该如何实现的。

总结;在任何给定的时间,您可以加载域模型的历史记录,查询其状态,并且可以加载事件处理器的历史记录,以确定尚未确认的工作。