2013-08-02 55 views
18

我有一個java對象,它不是一個從actor系統(Actor)中選擇actor的actor。可能的是,選定的actor在系統中不存在。如何檢查Akka actor是否存在(akka 2.2)?

在Java Api中,對於ActorSelection而言,ask()不存在,所以我無法發送和Identify消息給actor選擇並使用響應的發送者。

我試圖通過演員選擇將消息發送給演員來解決問題,然後對deadletter作出反應。但我沒有得到任何死路一條。

如果演員還活着或不存在,我該如何檢查ActorSelection?

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

哎呀,這是一個監督的,謝謝指點出來:https://www.assembla.com/spaces/akka/simple_planner#/ticket: 3532 –

回答

12

它看起來像Akka在的Java API上不支持ActorSelection。我玩了一些代碼,然後發現了一些可行的方法。看看這段代碼適合你:

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

我剛纔看着scala問題支持如何工作,並通過java掛鉤到它。這對我有效;我希望它適合你。

5

阿卡提供了一個功能,使用一個特殊的消息Identify獲得來自ActorSelectionActorRef。您不必爲此郵件使用ask()。只需將一個Identify消息傳遞給ActorSelection,並監聽將傳回給您的ActorIdentity消息。目前正是這種在阿卡文檔的例子:Identifying Actors via Actor Selection (Java)

此代碼是從示例獲取的和修改:顯示ActorPath,ActorSelection之間的關係

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

還有一個非常漂亮的graphic文檔中的Actor生命週期。

+0

我需要從一個普通的java對象中識別出這個actor,而不是來自另一個actor,所以我不能使用你的建議。不幸的是,將這個對象變成一個演員是不可能的。 – schrums

+0

啊我看到了,我忽略了這個約束。 ;)也許你可以在你的Java對象中產生一個小助手 - Actor來發送和接收Identify消息。 –

+0

這些步驟將是:1)化身一個幫手 - 演員(然後你有一個ActorRef爲此),2)使用包含你想要測試的ActorSelection的所有信息的ask()發送一條消息3)返回來自當他們到達時的演員。它可以工作...;) –

21

我最近發現了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 
} 

的一個問題,我仍然在調查的,在這個定義可能同時調用的方法(從其他演員)。因此,如果resolveOne調用失敗,因爲actor仍在創建中,您可能會獲得兩次嘗試創建actor的爭用條件。這可能會或可能不會成爲您的使用案例的問題

+1

我想,如果你想訪問一個子動作,你可以在actor上下文中使用'def child(name:String):Option [ActorRef]'方法。它應該幫助解決併發問題。另見:http://stackoverflow.com/questions/16268333/get-existing-or-create-new-akka-actor – skytteren

3

其他答案請注意,ActorSelection.resolveOne()可以處理此問題。

一個警告:在引擎蓋下,這通過向有問題的演員發送消息來工作。這意味着如果該演員很忙,則不會回覆,並且失敗(超時)。

在純粹的最佳實踐 - 阿卡,這可能是一個角落案例。在更混合的普通Java/Akka設置中,雖然很容易被搞砸。特別是,在一個actor的線程中的代碼不能找到該actor的引用。

0

使用版本2.3。4

一些Scala的例子,也許可以幫助

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

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