如何在Akka Persistence中坚持行为?

时间:2015-04-16 12:24:11

标签: scala akka event-sourcing akka-persistence

我有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
}

1 个答案:

答案 0 :(得分:1)

你在做什么看起来不错,只是我认为你应该首先在恢复过程中改变你的行为,然后更新状态(这里不是这种情况,但是你的状态可能会有一些验证限制)。

我能想到的唯一另一个选择是覆盖onshutdown处理程序,并保证在下载之前将自己整合并保存快照,以及初始化消息。通过这种方式,您可以确保在重新生成时未初始化,并且将收到init消息。像

这样的东西
onShutdown {
  context become uninit
  saveSnapshot(state)
  persist(Init)
}

重新启动时,您的uninit快照将首先收到一条初始消息,然后接收下一条消息。

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