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
。您会收到一个请求,从外部服务收集一些数据,并构建一个包含您需要发送到您的实体的所有内容的命令。
您当然不应该询问读方在您的写方实体内做出业务决策。您也不应该对来自其他实体的数据做出商业决策。
您的实体应该能够做出所有决定,因为它是模型的一致性边界。
我在这些情况下所做的是将PersistentEntityRef传递给异步操作,以便它可以向实体及其那些命令处理程序(不是生成异步计算的那个)发出命令,然后坚持事件。
只要记住这些都不是原子的,所以你必须考虑如果异步操作在发出命令的过程中失败,或者如果某些命令成功并且某些命令失败等等,会发生什么情况。假定您需要一些系统故障的重试机制。如果你构建你的命令处理程序是幂等的,它将帮助你处理重复项。
这一切都很好,但是当一个聚合可以引用另一个聚合内的实体(并且一般!)时,删除级联的一致性边界就变成了整个世界。当然,除非完全禁用删除,这可能是一种选择。 – silverberry
命令浓缩是另一种选择。谢谢。 – silverberry
我想我可以做preDelete来收集所有防止删除的实体或所有必须通过级联删除/更新的实体,然后才会实际发出执行这些操作的命令。 – silverberry