【问题标题】:How to persist behavior in Akka Persistence?如何在 Akka Persistence 中持久化行为?
【发布时间】:2015-04-17 21:41:30
【问题描述】:

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

【问题讨论】:

  • 您可以考虑为此使用Akka Persistent FSM,尽管它仍处于试验阶段。它持久化生成的事件以及状态转换,这可能很好地映射到您的应用所需的行为更改。

标签: scala akka event-sourcing akka-persistence


【解决方案1】:

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

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

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

重新启动时,您的 uninit 快照首先会收到一条 init 消息,然后是接下来的任何消息。

虽然我不确定它是否更好,但您应该能够避免存储该行为,但是您必须小心不要在不这样做的情况下死去。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-12
    • 2021-01-30
    • 2016-03-07
    • 2014-10-19
    • 1970-01-01
    • 2016-02-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多