我有一个java对象,它不是一个使用actorSelection(Path)从actor系统中选择actor的actor。系统中可能存在选定的actor。
在Java Api中,ActorSelection不存在ask(),因此我无法向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 :(得分:25)
我最近找到了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
}
我还在研究的一个问题是,定义它的方法可能同时被调用(来自其他actor)。因此,如果由于仍在创建actor而使resolveOne调用失败,则可能会出现两次尝试创建actor的竞争条件。这可能是也可能不是您的用例的问题
答案 1 :(得分:13)
看起来Akka对ActorSelection
的java api上的ask
不予支持。我玩了一些代码,但我发现了一些有用的东西。看看这段代码是否适合你:
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来支持支持工作并将其连接到它。这对我有用;我希望它适合你。
答案 2 :(得分:6)
Akka提供了使用特殊消息ActorRef
从ActorSelection
获取Identify
的功能。您不必使用ask()
来发送此消息。只需将Identify-message传递给ActorSelection,然后侦听将传递给您的ActorIdentity
消息。在Akka文档中有一个这样的例子:Identifying Actors via Actor Selection (Java)
此代码取自示例并已修改:
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中的ActorPath,ActorSelection和Actor Lifecycle之间的关系。
答案 3 :(得分:4)
正如其他答案所指出的那样,ActorSelection.resolveOne()
处理这个问题。
一个警告:在引擎盖下,这是通过向相关演员发送消息来实现的。这意味着如果该演员忙,它不会回复,这会失败(超时)。
在纯粹的最佳实践中 - 阿卡,这可能是一个角落。在一个更加混合的普通Java / Akka设置中,它很容易被咆哮。特别是,actor的线程中的代码找不到对该actor的引用。
答案 4 :(得分:1)
使用版本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)
}