2013-08-02 59 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) 
    }