2014-07-11 7 views
7

Frage:richtige Muster für den Zustand in einem Akka Schauspieler Akkumulieren

Was ist das richtige Muster Zustand in einem Akka Schauspieler zum Akkumulieren?

Kontext:

Lassen Sie uns sagen, dass ich ein paar Dienste haben, dass alle Rückgabedaten.

class ServiceA extends Actor { 
    def receive = { 
    case _ => sender ! AResponse(100) 
    } 
} 

class ServiceB extends Actor { 
    def receive = { 
    case _ => sender ! BResponse("n") 
    } 
} 

// ... 

Ich möchte ein Steuerungs-/Überwachungs Schauspieler haben, die alle diese Dienste Koordinaten zu sprechen und ihre Antworten zu verfolgen, dann eine Antwort mit allen Daten zurück an den ursprünglichen Absender senden.

class Supervisor extends Actor { 
    def receive = { 
    case "begin" => begin 
    case AResponse(id) => ??? 
    case BResponse(letter) => ??? 
    } 

// end goal: 
def gotEverything(id: Int, letter: String) = 
    originalSender ! (id, letter) 

    def begin = { 
    ServiceA ! "a" 
    ServiceB ! "b" 
    } 
} 

Wie Service-Antworten kommen, wie behalte ich alle diesen Zustand zusammen? Wie ich es verstehe, wenn ich den Wert von AResponse z. B. var aResponse: Int zuweisen würde, ändert sich diese Var ständig, wie verschiedene Nachrichten empfangen werden, und es ist nicht möglich für mich zu bleiben, während ich auf die Nachricht BResponse warte .

Ich realisiere, ich könnte ask verwenden und nur nest/flatMap Future 's, aber von was ich gelesen habe, ist das ein schlechtes Muster. Gibt es einen Weg all das ohne Futures zu erreichen?

+0

Warum sollte 'aResponse' mehr als einmal geändert werden? Sie senden nur eine Nachricht an 'ServiceA'. Was genau ist dein Ziel? Warte, bis du "AResponse" und "BResponse" erhältst und "gotEverything" mit ihren Werten rufst? – vptheron

+0

>> Was genau ist dein Ziel?Warten Sie, bis Sie AResponse und BResponse erhalten und gotEverything mit ihren Werten aufrufen? YES –

+0

Sie können Antworten in einer Liste mit einem Bezeichner oder einer Akteurref. Speichern – wedens

Antwort

15

Da auf Akteure nie gleichzeitig von mehreren Threads aus zugegriffen wird, können Sie beliebige Zustände in ihnen speichern und mutieren. Zum Beispiel können Sie dies tun:

Es gibt einen besseren Weg, jedoch. Sie können eine Art Zustandsmaschine mit Akteuren ohne explizite Zustandsvariablen emulieren. Dies geschieht unter Verwendung des become() Mechanismus.

class Supervisor extends Actor { 
    def receive = empty 

    def empty: Receive = { 
    case "begin" => 
     AService ! "a" 
     BService ! "b" 
     context become noResponses(sender) 
    } 

    def noResponses(originalSender: ActorRef): Receive = { 
    case AResponse(id) => context become receivedId(originalSender, id) 
    case BResponse(letter) => context become receivedLetter(originalSender, letter) 
    } 

    def receivedId(originalSender: ActorRef, id: WhateverId): Receive = { 
    case AResponse(id) => context become receivedId(originalSender, id) 
    case BResponse(letter) => gotEverything(originalSender, id, letter) 
    } 

    def receivedLetter(originalSender: ActorRef, letter: WhateverLetter): Receive = { 
    case AResponse(id) => gotEverything(originalSender, id, letter) 
    case BResponse(letter) => context become receivedLetter(originalSender, letter) 
    } 

    // end goal: 
    def gotEverything(originalSender: ActorRef, id: Int, letter: String): Unit = { 
    originalSender ! (id, letter) 
    context become empty 
    } 
} 

Dies kann etwas ausführlicher sein, aber es enthält keine expliziten Variablen; Alle Zustände sind implizit in den Parametern der Receive Methoden enthalten, und wenn dieser Zustand aktualisiert werden muss, wird die Empfangsfunktion des Aktors einfach umgeschaltet, um diesen neuen Zustand widerzuspiegeln.

Beachten Sie, dass der obige Code sehr einfach ist und es nicht richtig funktioniert, wenn es viele "ursprüngliche Absender" geben kann. In diesem Fall müssen Sie allen Nachrichten eine ID hinzufügen und diese verwenden, um zu ermitteln, welche Antworten zu welchem ​​"ursprünglichen Absender" -Zustand gehören, oder Sie können mehrere Akteure für jeden der "ursprünglichen Absender" erstellen.

1

Ich glaube Akka Weg ist Schauspieler-pro-Anfrage-Muster zu verwenden. Auf diese Weise, anstatt herauszufinden, welche Antworten dem entsprechen, erstellen Sie jedes Mal einen neuen Akteur, wenn Sie eine Anfrage erhalten. Dies ist sehr billig und passiert tatsächlich jedes Mal, wenn Sie fragen().

Diese Anfrage-Prozessoren (so wie ich sie nenne) haben normalerweise einfache Felder für Antworten. Und es ist nur eine Frage des einfachen Null-Vergleichs, um zu sehen, ob die Anfrage angekommen ist.

Wiederholungen/Fehler werden auch mit diesem Schema viel einfacher. Timeouts auch.

Verwandte Themen