2013-08-02 12 views
18

Ich habe ein Java-Objekt, das kein Akteur ist, der mit actorSelection (Path) Actors aus einem Actor-System auswählt. Es ist möglich, dass der ausgewählte Akteur im System nicht existiert.Wie kann ich prüfen, ob ein Akka Actor existiert (akka 2.2)?

In der Java-API existiert ask() nicht für ActorSelection, daher kann ich keine Nachricht an die Aktorauswahl senden und identifizieren und den Absender der Antwort verwenden.

Ich versuchte das Problem zu lösen, indem ich die Nachricht über die Aktorauswahl an den Aktor schickte und dann auf den Deadletter reagierte. Aber ich bekomme keine Deadletters.

Wie kann ich mit der ActorSelection überprüfen, ob der Schauspieler lebt oder nicht existiert?

ActorSystem system = ActorSystem.create("test"); 

//create test actor 
system.actorOf(Props.create(TestActor.class), "testActor"); 

//add dead letter listener to the system 
ActorRef eventBusActor = asys.actorOf(Props.create(EventBusActor.class), "eventbusactor"); 
system.eventStream().subscribe(eventBusActor, DeadLetter.class); 


//This works. The test actor receives the message  
ActorSelection a1 = asys.actorSelection("/user/testActor"); 
a1.tell("hello", ActorRef.noSender()); 

//This does not work and does not send dead letters  
ActorSelection a2 = asys.actorSelection("/user/doesnotexist"); 
a2.tell("hello", ActorRef.noSender()); 

//Does not compile, because ask needs an ActorRef as first argument 
ActorSelection a3 = asys.actorSelection("/user/test"); 
Future f = Patterns.ask(a3, new Identify(), 1000); 
+0

Oops helfen, dass als ein Versehen, vielen Dank für den Hinweis it out: https://www.assembla.com/spaces/akka/simple_planner#/ticket: 3532 –

Antwort

12

Es sieht aus wie Akka Unterstützung für ActorSelection auf der Java-API für ask. Ich habe ein wenig mit dem Code gespielt und etwas gefunden, das funktioniert. Sehen Sie, wenn dieser Code für Sie arbeitet:

import java.util.concurrent.TimeUnit; 

import scala.concurrent.Await; 
import scala.concurrent.Future; 

import akka.actor.ActorIdentity; 
import akka.actor.ActorRef; 
import akka.actor.ActorSelection; 
import akka.actor.ActorSystem; 
import akka.actor.Identify; 
import akka.actor.Props; 
import akka.pattern.AskableActorSelection; 
import akka.util.Timeout; 

public class AskTest { 

    public static void main(String[] args) throws Exception{ 
    ActorSystem sys = ActorSystem.apply("test"); 
    sys.actorOf(Props.create(TestActor.class), "mytest"); 

    ActorSelection sel = sys.actorSelection("/user/mytest"); 

    Timeout t = new Timeout(5, TimeUnit.SECONDS); 
    AskableActorSelection asker = new AskableActorSelection(sel); 
    Future<Object> fut = asker.ask(new Identify(1), t); 
    ActorIdentity ident = (ActorIdentity)Await.result(fut, t.duration()); 
    ActorRef ref = ident.getRef(); 
    System.out.println(ref == null); 
    } 
} 

Ich sah sie nur an, wie die scala fragen Unterstützung gearbeitet und in sie über Java angeschlossen. Das hat für mich funktioniert; Ich hoffe, es funktioniert für dich.

5

Akka bietet eine Funktionalität Identify eine ActorRef von einem ActorSelection mit einer speziellen Nachricht zu erhalten. Sie müssen ask() für diese Nachricht nicht verwenden. Übergeben Sie einfach eine Identifizierungsnachricht an die ActorSelection und warten Sie auf eine ActorIdentity Nachricht, die an Sie zurückgegeben wird. Es ist ein Beispiel für genau diese in den Akka docs: Identifying Actors via Actor Selection (Java)

Dieser Code aus dem Beispiel genommen und geändert:

final String identifyId = "1"; 

@Override 
public void onReceive(Object message) { 
    if (message instanceof ActorIdentity) { 
     ActorIdentity identity = (ActorIdentity) message; 
     if (identity.correlationId().equals(identifyId)) { 
      ActorRef ref = identity.getRef(); 
      if (ref == null) 
       // Actor does not exist 
      else { 
       // Actor does exist 
      } 
     } 
    } 
} 

Es gibt auch eine sehr schöne graphic, das zeigt die Beziehungen zwischen ActorPath, ActorSelection und der Actor Lifecycle in den Dokumenten.

+0

Ich muss den Akteur von einem normalen Java-Objekt und nicht von einem anderen Akteur identifizieren, daher kann ich Ihren Ratschlag nicht verwenden. Leider ist es nicht möglich, dieses Objekt in einen Schauspieler zu verwandeln. – schrums

+0

Ah ich sehe, ich habe diesen Zwang übersehen. ;) Vielleicht könntest du einen kleinen Helfer-Aktor in deinem Java-Objekt erzeugen, um die Identify-Nachrichten zu senden und zu empfangen. –

+0

Die Schritte wären: 1) Incarnate einen Helfer-Actor (dann haben Sie eine ActorRef dafür), 2) senden Sie eine Nachricht mit Ask() enthält alle Informationen für die ActorSelection, die Sie testen möchten 3) das Ergebnis aus der Schauspieler, als sie ankamen. Es könnte funktionieren ...;) –

21

Ich fand vor kurzem die ActorSelection.resolveOne Methode:

val name = "myActor" 
implicit val timeout = 5000 // Timeout for the resolveOne call 
system.actorSelection(name).resolveOne().onComplete { 
    case Success(actor) => actor ! message 

    case Failure(ex) => 
    val actor = system.actorOf(Props(classOf[ActorClass]), name) 
    actor ! message 
} 

Ein Problem, das ich untersuchen bin immer noch ist, wobei das Verfahren, wo dies definiert wird, könnte gleichzeitig (von anderen Akteuren) genannt. Daher ist es möglich, eine Race-Bedingung zu erhalten, bei der Sie versuchen, den Actor zweimal zu erstellen, wenn der resolveOne-Aufruf fehlschlägt, weil der Actor noch erstellt wird. Dies könnte oder könnte kein Problem für Ihren Anwendungsfall sein

+1

Ich schätze, wenn Sie versuchen, auf eine Kindaktion zuzugreifen, könnten Sie die 'def Kind (Name: String): Option [ActorRef]' Methode im Akteurkontext verwenden. Es sollte mit dem Concurrency-Problem helfen. Siehe auch: http://stackoverflow.com/questions/16268333/get-existing-or-create-new-akka-actor – skytteren

3

Wie andere Antworten beachten Sie, ActorSelection.resolveOne() behandelt dies.

Eine Warnung: Unter der Haube funktioniert dies durch Senden einer Nachricht an den betreffenden Akteur. Das heißt, wenn dieser Akteur beschäftigt ist, antwortet er nicht, und dies schlägt fehl (mit einer Zeitüberschreitung).

In Pure-Best-Practice-Akka ist dies wahrscheinlich ein Eckfall. In einem eher gemischten Java-Akka-Setup ist es jedoch leicht, sich zu verwirren. Insbesondere kann Code innerhalb eines Actor-Threads keinen Verweis auf diesen Actor finden.

0

Verwenden der Version 2.3.4

Einige Beispiel Scala, können vielleicht

val zed2 = Akka.system().actorSelection("path") 
    val fs:FiniteDuration = (100).millis 

    val x = zed2.resolveOne(fs).value 
    if (x.isDefined){ 
    println(x.get.isFailure) 
    }