Акка ФСМ Актер с тайником и распаковкой

Я хотел бы спрятать/распаковать с помощью 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

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


person Rohit    schedule 19.02.2017    source источник


Ответы (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()
  }
}

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

person Andrei T.    schedule 23.02.2017
comment
Я рад это слышать :) - person Andrei T.; 25.02.2017