DDD处理随时间推移聚合更新

时间:2017-12-28 17:34:15

标签: domain-driven-design event-sourcing aggregateroot

使用Event Sourcing,我有一个域,其中聚合应该不时更新。当我创建聚合时,我有一个到期时间(这可以是任意的),在那之后我必须更新实体的一些属性。 (这也可以使用UpdateCommand强制执行。)我记住了几个过程:

  1. 在创建聚合之后,我将聚合ID和到期时间存储在RDBMS中。
  2. 在cron作业中,我向数据库查询过期的聚合,并提交UpdateCommand
  3. 其他包括从读取端发出UpdateCommands(或事件?)。 使用saga来协调更新,这与第一个类似。但不管怎样,我必须存储到期时间。

    因此,我必须存储事件并以事务方式写入写入端的数据库。但是,我不确定为写入端(?)创建读取端是否是DDD世界中的正确解决方案,还是适用?有哪些推荐的解决方案?

4 个答案:

答案 0 :(得分:2)

我还需要在一段时间后过期运行一些命令。

例如,我需要在1年后发出ContractExpiredEventContractAggregate决定何时,但通常是1年)。问题是Aggregate必须是决定何时执行什么命令以及执行什么命令的聚合,因此这是一个Domain关注点而不是基础结构问题。

我是怎么做到的?我受到Udi Dahan's 视频的启发,在视频中他引用了术语Timeout。简而言之,Aggregate要求在经过一段时间后将命令发送给自己。它通过从命令处理程序产生它来做到这一点。基础CQRS框架获取scheduled command并将其持久保存在特殊存储库中。然后,cron job处理所有已调度的命令。

答案 1 :(得分:1)

ES和DDD之间有很好的兼容性。

  

但是,我不确定为写入端创建一个读取端(?)是否是DDD世界中的正确解决方案,还是适用?

是的,在您的情况下,它是域聚合的一部分(如果您谈论在写入端存储到期时间)。

  

因此,我必须存储事件并以事务方式写入写入端的数据库。

我建议你使用saga写入数据库。

答案 2 :(得分:1)

John Carmack, 1998

  

如果你不把时间视为输入值,那么在你做之前要考虑它 - 这是一个重要的概念

你应该寻找的模式是现实世界(时间在哪里)告诉聚合当前时间,聚合决定是否自己到期

有了这种模式,您可以使用任何您喜欢的策略来安排现实世界告诉汇总时间时。

您不需要在聚合中立即进行一致的调度,只需要一些幂等的消息处理和“至少一次”的传递过程。

  

聚合有一种方法可以根据当前时间进行更新,而不是盲目地进行更新。有时我必须从商店中获取正确的聚合,调用该方法并将更改存储回来(如果有的话),或者稍后重试,对吗?

是的,这是正确的想法。

请注意,如果在到期时间之后两次调用该方法,则第一次调用将加载历史记录,附加到期事件并存储更新的历史记录。 第二个调用加载历史记录,可以看到聚合已经过期,并且在不对历史记录进行任何更改的情况下退休。

答案 3 :(得分:1)

您还可以使用双时事件源。存储事件时,有两个日期:

  • 将事件添加到数据库的日期(createdAt
  • 必须应用事件的日期(validFrom

然后按照validFrom属性定义的顺序应用事件。

使用此功能,您可以:

  • 通过添加新事件(createdAt = nowvalidFrom = now - x)“修复过去”
  • 通过添加新事件(createdAt = nowvalidFrom = now + y)安排将来的事件

我建议在DDD Europe 2018上观看Thomas Pierrain的精彩视频:https://www.youtube.com/watch?v=xzekp1RuZbM