2017-02-19 4 views
2

würde Ich mag stashing tun/unstashing mit FSM Akka Acctor. Ich weiß nicht, wo ich die stash() und unstashAll() setzen soll.Akka FSM Schauspieler mit stashing und unstashing

Ich habe ein vereinfachtes Beispiel unten:

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") 
} 

Der Anfangszustand ist StateA. Wenn in StateA die Schauspieler nur Nachrichten vom Typ MessageA behandeln sollen. Wenn es eine andere Art von Nachricht (außer ChangeState) empfängt, sollte es es verstauen. Nach Erhalt einer Nachricht ChangeState sollte der Aktor zu StateB wechseln. Upon von StateA zu StateB ändern, sollte es alle Nachrichten unstash. Wenn in StateB der Aktor sollte nur Nachrichten des Typs MessageB behandeln.

Ich bin nicht sicher, wo genau die stash() und unstashAll() verwenden, um dies zu erreichen.

Die Ausgabe, die ich auf Laufen zu bringen ist:

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

Der Ausgang Ich mag würde, ist zu sehen:

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

Vielen Dank.

Antwort

5

Sie können dies auf der FSM unter Verwendung des onTransition Verfahren erreichen. Dies wird ausgeführt, wenn eine Statusänderung auftritt, und wir können diesen Moment verwenden, um alle Nachrichten zu löschen. Was Verstecke betrifft, müssen Sie es in der whenUnhandled Methode tun. Ich habe machte auch ein kleines Update, so dass Sie können Zyklus zwischen den Staaten:

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() 
    } 
} 

Lassen Sie mich wissen, wenn Sie weitere Fragen haben :)

+0

Vielen Dank @ andrei-t, es funktioniert. – Rohit

+0

Ich bin froh, das zu hören :) –