在Akka Typed持久化演员中创建子演员

3
假设使用Akka Typed实现的应用程序具有一个持久化actor。该持久化actor在其操作的一部分中创建短暂(或非持久化)子actor,每个子actor都有一个唯一的ID,并且这些ID是持久化状态的一部分。持久化actor还需要与其子actor进行通信,但我们不想将子actor的ActorRef持久化,因为它们不是状态的一部分。在恢复期间,持久化actor应该基于恢复的状态重新创建其子actor。这似乎不是一个非常不寻常的用例,我正在尝试找出最干净的实现方式。我可以在命令处理程序中的andThen Effect中创建子actor,该命令处理程序用于副作用,但是从那里没有办法保存子actor的ActorRef。这似乎是类型持久性API的一个更普遍的特征——对于持久化actor中的非持久化状态(在本例中可用于存储短暂的子actor ActorRef),非常难以实现。我想到的一个解决方案是创建一个“代理”actor来创建子actor,保持ID和ActorRef的映射,并根据ID转发消息。持久化actor保持对该代理actor的引用,并每次需要创建新子actor或向现有子actor之一发送内容时都会联系该代理actor。虽然我对此有好坏参半的感觉,但如果有人可以指出更好的解决方案,我将不胜感激。

你是如何恢复持久性Actor的?你使用快照还是只使用日志记录的事件? - Tim
没有对此有严格的要求,但最好两者兼备。 - s4nk
2个回答

1
如果您不使用快照,则持久性机制不会存储“State”对象,而是存储导致该“State”对象的“Event”序列。在恢复时,它只是按照它们发生的顺序重新播放这些“Event”,并且您的“eventHandler”将返回一个修改后的“State”对象,该对象反映了每个事件的影响。
这意味着“State”对象可以包含值,这些值本身没有被持久化,而仅仅是通过处理某些“Event”而设置的。实际上,它们是从“State”中的持久值派生的缓存值。
在您的情况下,导致创建短暂actor的操作将作为actor上的“Event”捕获。因此,您可以在“eventHandler”中创建瞬态actor,并将“ActorRef”放入新的“State”对象中。当actor恢复时,它将重播该事件,您的actor将重新创建短暂actor。
如果您正在使用快照,则我认为快照对象与您的State对象不必是相同类型,因此您可以在没有ActorRef的情况下拍摄状态,并在收到SnapshotOffer消息时重新创建它们。

这些是非常好的观点,感谢您的建议。实际上,我已经考虑在事件处理程序中创建子级别,但问题是,除了具有短暂和有限的生命周期(它们被创建,监督后台任务,并在完成后终止),子级别本身会对更广泛的系统产生副作用。这就是为什么我更愿意避免在重放事件时创建子级别,并将该部分延迟到恢复完成之后。 - s4nk
1
如果可输入的持久化actor可以具有两种状态:持久化状态(仅由eventHandler修改)和非持久化状态(可以在actor的任何地方进行修改,无论是在eventHandler、commandHandler还是post-recovery回调中),那将是很棒的。 - s4nk
@s4nk 我认为争论的观点是,拥有“非持久状态”会破坏模型的纯净性,因为这意味着你无法完全从持久化数据中恢复状态,因此也无法完全恢复演员。 - Tim

1
“类型化持久性的设计目标是从事件(或从快照和自那个快照以来的事件)完全恢复状态。一般来说,拥有非持久状态的唯一方法是将EventSourcedBehavior包装在Behaviors.setup块中,该块设置状态。其中之一是在setup中使用某种可变状态(例如var或(可能是排他或)可变集合),它由命令/事件/恢复处理程序操作。更加不可变的替代方案是在setup中定义一个不可变的fixture,其中包括在setup中生成的子actor来管理非持久状态。您还可以将实体ID或其他至少在此实体化身中为不可变的内容放入fixture中。”

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接