【问题标题】:Akka FSM Actor with stashing and unstashing具有 stashing 和 unstashing 的 Akka FSM Actor
【发布时间】:2017-02-19 19:38:04
【问题描述】:

我想使用 FSM Akka Acctor 进行存储/取消存储。我不知道把stash()unstashAll() 放在哪里。

我有一个简化的例子如下:

import akka.actor.{ActorSystem, FSM, Props, Stash}

trait TestState
case object StateA extends TestState
case object StateB extends TestState

case class TestData()

case class MessageA(msg: String)
case class MessageB(msg: String)
case object ChangeState

class TestFSM extends FSM[TestState, TestData] with Stash {

  startWith(StateA, TestData())

  when(StateA) {
    case Event(MessageA(msgA), _) =>
      println(s"In StateA: $msgA")
      stay()
    case Event(ChangeState, _) =>
      println("Changing state from A to B")
      goto(StateB)
  }

  when(StateB) {
    case Event(MessageB(msgB), _) =>
      println(s"In StateB: $msgB")
      stay()
  }

  whenUnhandled {
    case Event(e, _) =>
      println(s"Unhandled event: $e")
      stay()
  }
}

object TestFSM extends App {
  val system = ActorSystem("test-system")
  val actor = system.actorOf(Props[TestFSM])

  actor ! MessageA("Apple 1")
  actor ! MessageB("Banana 1")
  actor ! MessageA("Apple 2")

  actor ! ChangeState

  actor ! MessageB("Banana 2")
}

初始状态为StateA。 当在StateA 中时,actor 应该只处理MessageA 类型的消息。如果它收到任何其他类型的消息(ChangeState 除外),它应该将其隐藏。收到消息ChangeState 后,actor 应更改为StateB。 从StateA 更改为StateB 后,它应该取消隐藏所有消息。 在 StateB 中时,actor 应该只处理 MessageB 类型的消息。

我不确定在哪里使用stash()unstashAll() 来实现这一点。

我运行的输出是:

In StateA: Apple 1
Unhandled event: MessageB(Banana 1)
In StateA: Apple 2
Changing state from A to B
In StateB: Banana 2

我想看到的输出是:

In StateA: Apple 1
In StateA: Apple 2
Changing state from A to B
In StateB: Banana 1
In StateB: Banana 2

非常感谢。

【问题讨论】:

    标签: scala akka akka-fsm


    【解决方案1】:

    您可以通过在FSM 上使用onTransition 方法来实现此目的。这会在状态发生变化时执行,我们可以利用那一刻来取消存储所有消息。至于存储,您需要在whenUnhandled 方法中进行。我还做了一个小更新,以便您可以在状态之间循环:

    class TestFSM extends FSM[TestState, TestData] with Stash {
      startWith(StateA, TestData())
    
      when(StateA) {
        case Event(MessageA(msgA), _) =>
          println(s"In StateA: $msgA")
          stay()
        case Event(ChangeState, _) =>
          println("Changing state from A to B")
          goto(StateB)
      }
    
      when(StateB) {
        case Event(MessageB(msgB), _) =>
          println(s"In StateB: $msgB")
          stay()
        case Event(ChangeState, _) =>
          println("Changing state from B to A")
          goto(StateA)
      }
    
      /**
        * Here we can stash all messages. For example when we're in state A,
        * we handle both `MessageA` and `ChangeState` messages, but we don't
        * handle `MessageB` instances which will end up here. The opposite
        * happens when we're in state B.
        */
      whenUnhandled {
        case _: Event =>
          stash()
          stay()
      }
    
      // When transitioning into another state, unstash all messages.
      onTransition {
        case StateA -> StateB => unstashAll()
        case StateB -> StateA => unstashAll()
      }
    }
    

    如果您还有其他问题,请告诉我:)

    【讨论】:

    • 我很高兴听到这个消息 :)
    猜你喜欢
    • 1970-01-01
    • 2015-10-23
    • 2020-11-05
    • 2020-08-24
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 2016-02-15
    • 2012-06-23
    相关资源
    最近更新 更多