0

PersistentActor对于给定的事件,我有一个可以改变他的状态和/或他的行为的方法。对于持久化状态没有问题,但事实证明我需要将行为也作为状态的一部分持久化,否则在从快照恢复失败的情况下将无法正确初始化,因为快照只携带状态而不是行为。如何正确实现这一目标?

目前,我所做的是保存状态和行为的元组,但我不知道这是否是正确的方法。我愿意接受任何形式的建议和想法。FWIW,这种参与者的用例是作为集群分片的一个条目,我需要每个条目使用 (become/unbecome) 来经历几个状态,并保持条目的状态以及它们所处的行为。非常感谢。

这是说明问题的代码:

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
}
4

1 回答 1

1

你所做的看起来不错,只是我认为一般来说你应该首先在恢复期间改变你的行为,然后更新状态(这里不是这种情况,但你的状态通常可能存在一些验证约束)。

我能想到的唯一其他选择是覆盖 onshutdown 处理程序并保证您已将自己统一化并在关闭之前保存快照以及初始化消息。通过这种方式,您可以保证在重生时您未初始化,并将收到初始化消息。就像是

onShutdown {
  context become uninit
  saveSnapshot(state)
  persist(Init)
}

重新启动时,您的 uninit 快照将首先收到一条初始化消息,然后是接下来的任何内容。

虽然我不确定它会好得多,但你应该能够避免存储行为,但是你必须小心不要不这样做就死了。

于 2015-04-17T13:41:30.683 回答