Акка ФСМ Актер со скрытием и снятием

Я хотел бы делать скрытие / разборку с 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 актер должен обрабатывать только сообщения типа MessageA, Если он получает любой другой тип сообщения (за исключением ChangeState) это должно спрятать это. После получения сообщения ChangeState, актер должен измениться на StateB, При переходе от StateA в StateB, он должен распаковать все сообщения. Когда в StateB актер должен обрабатывать только сообщения типа 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

Большое спасибо.

1 ответ

Решение

Вы можете достичь этого с помощью onTransition метод на FSM, Это выполняется, когда происходит изменение состояния, и мы можем использовать этот момент, чтобы распаковать все сообщения. Что касается скрытия, вам нужно сделать это в 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()
  }
}

Позвольте мне знать, если у вас есть еще вопросы:)

Другие вопросы по тегам