2013-08-02 6 views
18

Ho un oggetto java che non è un attore che seleziona attori da un sistema di attori con actorSelection (Path)). È possibile che l'attore selezionato non esista nel sistema.Come posso verificare se esiste un attore Akka (akka 2.2)?

Nel Java Api ask() non esiste per ActorSelection, quindi non è possibile inviare e identificare il messaggio alla selezione dell'attore e utilizzare il mittente della risposta.

Ho provato a risolvere il problema inviando il messaggio all'attore attraverso la selezione dell'attore e poi reagendo alla lettera. Ma non ricevo nessuna lettera morta.

Come posso verificare con ActorSelection se l'attore è vivo o non esiste?

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, che, come una svista, grazie per segnalarlo: https://www.assembla.com/spaces/akka/simple_planner#/ticket: 3532 –

risposta

12

Sembra che Akka abbia lasciato il supporto per ActorSelection su java api per ask. Ho giocato un po 'con il codice e ho trovato qualcosa che funziona comunque. Vedere se questo codice funziona per voi:

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

Ho appena guardato come alla Scala chiedere supporto lavorato e agganciato in esso tramite Java. Questo ha funzionato per me; Spero che funzioni per te.

5

Akka fornisce una funzionalità per ottenere un ActorRef da un ActorSelection con un messaggio speciale Identify. Non è necessario utilizzare ask() per questo messaggio. Basta passare un messaggio di identificazione a ActorSelection e ascoltare un messaggio ActorIdentity che verrà passato a te. V'è un esempio proprio per questo nella documentazione Akka: Identifying Actors via Actor Selection (Java)

Questo codice è preso dall'esempio e modificato:

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

C'è anche una bella graphic che mostra le relazioni tra ActorPath, ActorSelection e the Actor Lifecycle nei documenti.

+0

Devo identificare l'attore da un normale oggetto java, non da un altro attore, quindi non posso usare il tuo consiglio. Sfortunatamente non è possibile cambiare questo oggetto in un attore. – schrums

+0

Ah capisco, ho trascurato quel vincolo. ;) Forse potresti generare un piccolo aiuto-attore all'interno del tuo oggetto Java per il solo scopo di inviare e ricevere i messaggi di identificazione. –

+0

I passaggi sarebbero: 1) Incarnare un helper-Actor (quindi hai un ActorRef per questo), 2) inviarlo un messaggio usando ask() contenente tutte le informazioni per la ActorSelection che vuoi testare 3) restituire il risultato dal Attore quando sono arrivati. Potrebbe funzionare ...;) –

21

Recentemente ho trovato il metodo 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 che sto ancora indagando è, il metodo in cui questo è definito potrebbe essere chiamato contemporaneamente (da altri attori). Pertanto è possibile ottenere una condizione di competizione in cui si tenta di creare l'attore due volte se la chiamata a resolveOne non riesce perché l'attore è ancora in fase di creazione. Questo potrebbe o potrebbe non essere un problema per il tuo caso d'uso

+1

Immagino che se stai provando ad accedere ad un'azione figlio puoi usare il metodo 'def child (name: String): Option [ActorRef]' nel contesto dell'attore. Dovrebbe aiutare con il problema della concorrenza. Vedi anche: http://stackoverflow.com/questions/16268333/get-existing-or-create-new-akka-actor – skytteren

3

Come altre risposte nota, ActorSelection.resolveOne() gestisce questo.

Un avvertimento: sotto il cofano, questo funziona inviando un messaggio all'attore in questione. Il che significa che se quell'attore è occupato, non risponderà, e questo fallisce (con un timeout).

In puro-best-pratica-Akka, questo è probabilmente un caso d'angolo. In una configurazione mista mista di Java/Akka normale, è facile essere ringhiati. In particolare, il codice all'interno del thread di un attore non può trovare un riferimento a quell'attore.

0

Utilizzo della versione 2.3.4

Qualche esempio Scala, forse può aiutare

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

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