我有一个演员系统,目前接受命令/消息。这些演员的状态坚持Akka.Persistance。我们现在想为这个actor系统构建查询系统。基本上我们的问题是我们想要一种方法来获得这些特定参与者的所有状态的聚合/列表。虽然我没有严格订阅CQRS模式,但我认为这可能是一种巧妙的方式。
我最初的想法是让一个参与者进行查询,将其作为其状态的一部分保存为正在执行“数据写入”的其他参与者的状态的聚合。要做到这一点,这个演员将订阅它感兴趣的演员,并且当这些演员经历某种状态变化时,他们只会向查询演员发送他们的状态。这是怎么回事?有更好的方法吗?
答案 0 :(得分:1)
我对实现此类模式的建议是在此处为您的演员使用pub-sub和push-and-pull消息传递的组合。
对于每个"聚合,"此actor应该能够订阅您要查询的各个子actor的事件。只要孩子的状态发生变化,就会将消息推送到所有订阅的聚合中,并且每个聚合状态都会自动更新。
当一个新的aggegrate上线并且需要检索错过的状态(从它存在之前)它应该能够从每个孩子拉出当前状态并使用它来构建其当前状态,使用来自孩子的增量更新保持其对儿童状态的总体看法一致。
这是我用于此类工作的模式,它在本地开箱即用。通过网络,您可能必须确保可传递性保证,并且通常很容易做到。您可以在那里阅读更多有关如何执行此操作的信息:https://petabridge.com/blog/akkadotnet-at-least-once-message-delivery/
答案 1 :(得分:1)
一些Akka.Persistence后端(即那些使用SQL的人)也实现了一种称为Akka.Persistence.Query的东西。它允许您订阅生成的事件流,并将其用作Akka.Streams语义的源。
如果您正在使用SQL-journal,则需要 Akka.Persistence.Query.Sql 和 Akka.Streams 包。从那里你可以为特定演员创建一个实时(意味着不断更新)的事件来源,并将它用于你喜欢的任何操作,即打印它们:
using (var system = ActorSystem.Create("system"))
using (var materializer = system.Materializer())
{
var queries = Sys.ReadJournalFor<SqlReadJournal>(SqlReadJournal.Identifier)
queries.EventsByPersistenceId("<persistence-id>", 0, long.MaxValue)
.Select(envelope => envelope.Event)
.RunForEach(e => Console.WriteLine(e), materializer);
}