我有PersistentActor
,对于特定事件,可以改变他的状态和/或他的行为。为了保持状态没有问题,但事实证明我需要将该行为也作为状态的一部分持久化,否则在从快照恢复故障的情况下它将无法正确初始化,因为快照仅承载国家而不是行为。如何正确实现这一目标?
目前,我所做的是保存状态和行为的元组,但我不知道这是否是正确的方法。我愿意接受任何建议和想法。 FWIW,这种actor的用例是作为集群分片的一个条目,我需要每个条目使用(成为/不成为)并保持条目的状态以及它们所处的行为。非常感谢。
以下是说明问题的代码:
class FooActor extends PersistentActor with ActorLogging {
import FooActor._
var state: List[String] = Nil
def updateState(e: FooEvent): Unit = e match {
case Initialized ⇒ context become initialized
case Uninitialized ⇒ context become uninitialized
case Fooed(data) ⇒ state = data :: state
}
def uninitialized: Receive = {
case Init ⇒ persist(Initialized)(updateState)
}
def initialized: Receive = {
case Foo(data) ⇒ persist(Fooed(data))(updateState)
case Uninit ⇒ persist(Uninitialized)(updateState)
case Snap ⇒ saveSnapshot((state, receiveCommand)) // how to persist current behavior also?
}
def receiveRecover: Receive = {
case e: FooEvent ⇒ updateState(e)
// here, if I don't persist the behavior also, when the state is
// recovered, the actor would be in the uninitialized behavior and
// thus will not process any Foo commands
case SnapshotOffer(_, (_state: List[String], behavior: Receive)) ⇒
state = _state
context become behavior
}
def receiveCommand: Receive = uninitialized
val persistenceId = "foo-pid"
}
object FooActor {
case object Init
case object Uninit
case object Snap
case class Foo(data: String)
trait FooEvent
case object Initialized extends FooEvent
case object Uninitialized extends FooEvent
case class Fooed(data: String) extends FooEvent
}
答案 0 :(得分:1)
你在做什么看起来不错,只是我认为你应该首先在恢复过程中改变你的行为,然后更新状态(这里不是这种情况,但是你的状态可能会有一些验证限制)。
我能想到的唯一另一个选择是覆盖onshutdown处理程序,并保证在下载之前将自己整合并保存快照,以及初始化消息。通过这种方式,您可以确保在重新生成时未初始化,并且将收到init消息。像
这样的东西onShutdown {
context become uninit
saveSnapshot(state)
persist(Init)
}
重新启动时,您的uninit快照将首先收到一条初始消息,然后接收下一条消息。
虽然我不确定它会好得多,但你应该能够避免存储这些行为,但是如果不这样做,你必须要小心,不要死。