2017-02-19 32 views
2

Я хотел был бы сделать stashing/unpashing с FSM Akka Acctor. Я не знаю, где положить stash() и unstashAll().Акка FSM Актер со скрежетом и неустойчивостью

У меня есть упрощенный пример ниже:

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 

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

ответ

5

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

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

+0

Большое спасибо @ АНДРЕЙ-т, это работает. – Rohit

+0

Я рад, что слышу это :) –