J'ai un Java qui n'est pas un acteur qui sélectionne les acteurs d'un système d'acteurs avec acteurSelection (Path)). Il est possible que l'acteur sélectionné n'existe pas dans le système.
Dans le Java Api ask () n'existe pas pour ActorSelection, donc je ne peux pas envoyer et identifier de 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 tout de même le message à l'acteur via la sélection d'acteur puis en réagissant à la lettre morte. Mais je ne reçois aucune lettre d’attente.
Comment puis-je vérifier auprès d'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);
Il semble qu'Akka ait laissé de côté le support de ActorSelection
sur le Java api pour ask
. J'ai un peu joué avec le code et j'ai trouvé quelque chose qui fonctionnait cependant. Voyez 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 voir comment le support scala ask a fonctionné et s'est connecté via Java. Cela a fonctionné pour moi; j'espère que cela fonctionne pour vous.
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 j'étudie toujours est que la méthode où cela est défini peut être appelée simultanément (à partir d'autres acteurs). Par conséquent, il est possible d'obtenir une condition de concurrence critique dans laquelle vous essayez de créer l'acteur deux fois si l'appel resolOne échoue car l'acteur est toujours en cours de création. Cela pourrait ou non être un problème pour votre cas d'utilisation
Akka fournit une fonctionnalité pour obtenir un ActorRef
à partir d'un ActorSelection
en utilisant un message spécial Identify
. Vous n'avez pas besoin d'utiliser ask()
pour ce message. Passez simplement un message Identify à ActorSelection et écoutez un message ActorIdentity
qui vous sera renvoyé. Il y a un exemple pour exactement cela dans les documents Akka: Identifier les acteurs via la sélection d'acteurs (Java)
Ce code est extrait de l'exemple et modifié:
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 un très joli graphique qui montre les relations entre ActorPath, ActorSelection et l'Actor Lifecycle dans les documents.
Comme d'autres réponses le notent, 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 Akka, la meilleure pratique, c'est probablement un cas d'angle. Dans une configuration plus mixte normale Java/Akka, il est facile de se faire gronder cependant. En particulier, le code dans le thread d'un acteur ne peut pas trouver de référence à cet acteur.
Utilisation de la version 2.3.4
Certains Scala, peut 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)
}