Lagom:命令处理程序中的异步操作

Lagom:命令处理程序中的异步操作

问题描述:

在Lagom中,当命令处理程序必须执行一些异步操作时,你会做什么?例如:Lagom:命令处理程序中的异步操作

override def behavior = Actions().onCommand[MyCommand, Done] { 
    case (cmd, ctx, state) => 
    // some complex code that performs asynchronous operations 
    // (for example, querying other persistent entities or the read-side 
    // by making calls that return Future[...] and composing those), 
    // as summarized in a placeholder below: 
    val events: Future[Seq[Event]] = ??? 
    events map { 
     xs => ctx.thenPersistAll(xs: _*) {() => ctx.reply(Done) } 
    } 
} 

与这样的代码的问题是,编译器期望的命令处理程序返回Persist,不Future[Persist]

这样做的目的是为了确保事件以正确的顺序持续存在(也就是说,事先生成的事件必须保存在事件之后)。但是不能通过适当管理事件补偿来处理,以便日记总是正确地命令它们,而不管它们何时实际保存?

在这种情况下,当命令处理足够复杂以至于需要从命令处理程序进行异步调用时,会发生什么情况?

在邮件列表上还有一个类似的问题,James的答案是。 https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!topic/lagom-framework/Z6lynjNTqgE

总之,你在CQRS应用实体是一致的边界,应该只依赖于数据,它是立即可用里面,不在外面(没有调用外部服务)。

您可能正在寻找什么叫Command Enrichment。您会收到一个请求,从外部服务收集一些数据,并构建一个包含您需要发送到您的实体的所有内容的命令。

您当然不应该询问读方在您的写方实体内做出业务决策。您也不应该对来自其他实体的数据做出商业决策。

您的实体应该能够做出所有决定,因为它是模型的一致性边界。

+0

这一切都很好,但是当一个聚合可以引用另一个聚合内的实体(并且一般!)时,删除级联的一致性边界就变成了整个世界。当然,除非完全禁用删除,这可能是一种选择。 – silverberry

+0

命令浓缩是另一种选择。谢谢。 – silverberry

+0

我想我可以做preDelete来收集所有防止删除的实体或所有必须通过级联删除/更新的实体,然后才会实际发出执行这些操作的命令。 – silverberry

我在这些情况下所做的是将PersistentEntityRef传递给异步操作,以便它可以向实体及其那些命令处理程序(不是生成异步计算的那个)发出命令,然后坚持事件。

只要记住这些都不是原子的,所以你必须考虑如果异步操作在发出命令的过程中失败,或者如果某些命令成功并且某些命令失败等等,会发生什么情况。假定您需要一些系统故障的重试机制。如果你构建你的命令处理程序是幂等的,它将帮助你处理重复项。