java - tutorial - ¿Cómo puedo verificar si existe un actor Akka(akka 2.2)?
akka tutorial (5)
Akka proporciona una funcionalidad para obtener un ActorRef
de un ActorSelection
utilizando un mensaje especial Identify
. No tienes que usar ask()
para este mensaje. Simplemente pase un mensaje de identificación a ActorSelection y escuche un mensaje de ActorIdentity
que le será devuelto. Hay un ejemplo para exactamente esto en los documentos de Akka: Identificación de actores a través de la selección de actores (Java)
Este código se toma del ejemplo y se modifica:
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
}
}
}
}
También hay un graphic muy bonito que muestra las relaciones entre ActorPath, ActorSelection y el Actor Lifecycle en los documentos.
Tengo un objeto java que no es un actor que selecciona actores de un sistema de actores con actorSelection (Path)). Es posible que el actor seleccionado no exista en el sistema.
En la Api de Java, ask () no existe para ActorSelection, por lo que no puedo enviar e identificar mensajes a la selección de actores y usar el remitente de la respuesta.
Intenté resolver el problema enviando el mensaje al actor de todos modos a través de la selección del actor y luego reaccionando al deadletter. Pero no me sale ningún deadletters.
¿Cómo puedo verificar con la Selección de actores si el actor está vivo o no existe?
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);
Como señalan otras respuestas, ActorSelection.resolveOne()
maneja esto.
Una advertencia: debajo del capó, esto funciona enviando un mensaje al actor en cuestión. Lo que significa que si el actor está ocupado, no responderá, y esto falla (con un tiempo de espera).
En las mejores prácticas de Akka, este es probablemente un caso de esquina. Sin embargo, en una configuración más mixta normal de Java / Akka, es fácil quedar atrapado. En particular, el código dentro del hilo de un actor no puede encontrar una referencia a ese actor.
Parece que Akka dejó el soporte para ActorSelection
en la API de Java para ask
. Jugué un poco con el código y encontré algo que funciona bien. Mira si este código te funciona:
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);
}
}
Acabo de ver cómo funcionaba el soporte de Scala Ask y lo conecté a través de Java. Esto funcionó para mí; Espero que te funcione.
Recientemente encontré el método 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 problema que todavía estoy investigando es que el método donde se define esto podría llamarse simultáneamente (de otros actores). Por lo tanto, es posible obtener una condición de carrera en la que intenta crear el actor dos veces si falla la llamadaresignación de una llamada porque el actor aún se está creando. Esto podría o no ser un problema para su caso de uso
Usando la versión 2.3.4
Un ejemplo de Scala, tal vez pueda ayudar
val zed2 = Akka.system().actorSelection("path")
val fs:FiniteDuration = (100).millis
val x = zed2.resolveOne(fs).value
if (x.isDefined){
println(x.get.isFailure)
}