2013-08-02 4 views
18

J'ai un objet java qui n'est pas un acteur qui sélectionne des acteurs d'un système d'acteur avec actorSelection (Path)). Il est possible que l'acteur sélectionné n'existe pas dans le système.Comment puis-je vérifier si un acteur Akka existe (akka 2.2)?

Dans l'Api Java, ask() n'existe pas pour ActorSelection, donc je ne peux pas envoyer et identifier un message à la sélection d'acteur et utiliser l'expéditeur de la réponse.

J'ai essayé de résoudre le problème en envoyant quand même le message à l'acteur via la sélection de l'acteur puis en réagissant à la lettre. Mais je ne reçois aucune lettre d'information. Comment puis-je vérifier avec Actorselection si l'acteur est vivant ou n'existe pas?

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, que comme un oubli, merci de le faire remarquer: https://www.assembla.com/spaces/akka/simple_planner#/ticket: 3532 –

Répondre

12

Il semble que Akka ait quitté le support pour ActorSelection sur l'API Java pour ask. J'ai un peu joué avec le code et j'ai trouvé quelque chose qui fonctionne bien. Voir si ce code fonctionne pour vous:

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

Je viens de regarder comment le scala demander un soutien travaillé et accroché dans via java. Cela a fonctionné pour moi; J'espère que ça marchera pour toi.

5

fournit une fonctionnalité Akka pour obtenir une ActorRef d'un ActorSelection en utilisant un message spécial Identify. Vous n'avez pas besoin d'utiliser ask() pour ce message. Il suffit de passer un message Identify à l'ActorSelection et d'écouter un message ActorIdentity qui vous sera transmis. Il est un exemple pour exactement cela dans AKKA docs: Identifying Actors via Actor Selection (Java)

Ce code est tiré de l'exemple et modified:

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

Il y a aussi une très belle graphic qui montre les relations entre ActorPath, ActorSelection et le cycle de vie de l'acteur dans les docs.

+0

Je dois identifier l'acteur d'un objet java normal, pas d'un autre acteur, donc je ne peux pas utiliser votre conseil. Malheureusement, il n'est pas possible de changer cet objet en acteur. – schrums

+0

Ah je vois, j'ai négligé cette contrainte. ;) Peut-être que vous pourriez générer un petit assistant-acteur dans votre objet Java dans le seul but d'envoyer et de recevoir les messages d'identification. –

+0

Les étapes seraient: 1) Incarner un assistant-acteur (alors vous avez un ActorRef pour cela), 2) lui envoyer un message en utilisant ask() contenant toutes les informations pour l'ActorSelection que vous voulez tester 3) retourner le résultat de la Acteur quand ils sont arrivés. Cela pourrait fonctionner ...;) –

21

J'ai récemment trouvé la méthode ActorSelection.resolveOne:

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 
} 

Un problème que je suis en train de rechercher est la méthode où est défini ce qu'on pourrait appeler en même temps (d'autres acteurs). Par conséquent, il est possible d'obtenir une condition de concurrence dans laquelle vous essayez de créer l'acteur deux fois si l'appel de resolveOne échoue car l'acteur est toujours en cours de création. Cela peut ou peut ne pas être un problème pour votre cas d'utilisation

+1

Je suppose que si vous essayez d'accéder à une action enfant, vous pouvez utiliser la méthode 'def enfant (name: String): Option [ActorRef]' dans le contexte de l'acteur. Cela devrait aider avec le problème de concurrence. Voir aussi: http://stackoverflow.com/questions/16268333/get-existing-or-create-new-akka-actor – skytteren

3

Comme le remarquent d'autres réponses, ActorSelection.resolveOne() gère cela.

Un avertissement: Sous le capot, cela fonctionne en envoyant un message à l'acteur en question. Ce qui signifie que si cet acteur est occupé, il ne répondra pas, et cela échoue (avec un timeout).

Dans pure-best-pratique-Akka, c'est probablement un cas-coin. Dans une configuration plus normale de Java/Akka, il est facile de s'embarrasser. En particulier, le code dans le fil d'un acteur ne peut pas trouver une référence à cet acteur.

0

Utilisation de la version 2.3.4

Quelques exemples Scala, peut-être aider

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

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