2017-02-19 78 views
2

我想做存储与FSM Akka存储/摆动。我不知道把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 

非常感谢。

回答

5

您可以通过在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() 
    } 
} 

让我知道,如果你有任何问题:)

+0

非常感谢@安德烈-T,它的工作原理。 – Rohit

+0

我很高兴听到:) –