【问题标题】:Updating last accessed time when separating Commands and Queries分离命令和查询时更新上次访问时间
【发布时间】:2015-01-27 15:04:40
【问题描述】:

考虑一个函数:IsWalletValid(walletID)。如果 walletID 存在于数据库中,则返回 true,并更新“last_accessed_time”字段。

一个任务会定期运行以删除任何在一段时间内未访问的钱包。

对于我们想要做的事情来说,这似乎是一个简单的解决方案,但 IsWalletValid() 有一个副作用,因为它会写入数据库。

我们是否应该添加一个额外的“UpdateLastAccessedTime(walletID)”函数?每次调用 IsWalletValid() 时,我们还需要记住调用 UpdateLastAccessedTime(walletID)。

【问题讨论】:

  • 为什么需要更新last_accessed_time字段?
  • 如果几天没有人访问某个钱包,则不再需要它,可以将其删除。
  • CQRS 最适合事件溯源,否则重建二级(持久)存储变得非常困难。使用事件溯源,你永远不会删除任何东西,所以如果你想删除钱包,我想知道 CQRS 是否是正确的架构..?
  • 您对问题的描述中缺少一些内容:为什么用户需要检查自己的钱包是否有效?如果您可以更多地用业务术语而不是实现来描述问题,那么给出答案会更容易。
  • 这是一个有趣的问题,由于有人查看了一条数据,它改变了系统。也许你应该重新审视这个要求。听起来您正在重新实现 LRU 缓存(如果有的话)。

标签: cqrs


【解决方案1】:

验证钱包是否有效并更新其 last_accessed_time 字段是否需要在事务上保持一致 (ACID)?您可以在这里使用最终一致性:

方法IsWalletValid 发布WalletAccessed 事件,然后事件处理程序异步更新last_accessed_time

【讨论】:

  • 我非常不同意这个答案(我相信大多数 CQRS 追随者会同意我的观点):查询应该从不发布事件。只有命令发布事件。
  • 是的,我同意在这种情况下,查询端不应该改变系统,即引发事件。
  • @JoshKodroff 为什么不呢?事件表明您的系统中发生了有趣的事情,无论是状态更改(域事件)、发送的电子邮件(集成事件)还是执行的查询(基础设施或在这种特定情况下,域事件)。你对命令错了:命令不发布事件,命令 change 聚合状态。聚合负责发布事件。如果IsWalletValid 有副作用,我更愿意将其显式建模为事件,而不是在读取端更新域。
  • @boz 发布事件从不改变系统。只有命令会改变聚合状态。
  • @boz Luiz 的评论是正确的。 Luiz,我并不是要暗示命令本身发布了事件。 Evecuting 命令发布事件。 “聚合”的概念甚至没有必要——我只是将其视为命令处理程序。为了使事情在语义上保持一致,我会在发出查询时执行一个命令,例如MarkWalletTouched,但我想如果在执行查询时引发事件,这不是世界末日。
【解决方案2】:

如果last_accessed_time 未被域逻辑访问以对任何写处理做出决定,这可能只是只读投影的一个方面。似乎这与其他更详细的读取审计问题相同。仅仅因为正在写入和维护数据并不意味着它必然需要成为系统写入模型的一部分。但是,如果您确实希望将其作为域的一部分来实现,并且可能存储在同一事件存储中,则可以将其视为被审计的原始聚合边界之外的单独审计上下文。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多