Reputation: 3201
I tried two ways:
Use Await.result
Await.result(context.actorSelection("akka://Post/user/John").resolveOne(3 seconds), 10 seconds)
Get future value manually
context.actorSelection("akka://Post/user/John").resolveOne(3 seconds).value.get.get
But I have that feeling I'm doing something wrong.
Code of my actor:
def receive: Receive = {
case "msg" ⇒ {
...
val reader = Await.result(context.actorSelection("akka://Post/user/John").resolveOne(3 seconds), 10 seconds)
reader ! data
}
}
Upvotes: 0
Views: 433
Reputation: 14414
You should never block inside an Actor's receive
loop. At best it wastes resources, at worse it could lead to a deadlock where the resolution cannot happen because all threads in the thread pool are already in use.
Your best options are:
Send the message directly to the actorSelection
You can just call tell
directly on the actor selection. Of course, you don't know if the resolution succeeds. And if this happens a lot, it's certainly less efficient than having the actorRef hang around.
context.actorSelection("akka://Post/user/John").resolveOne(3 seconds) ! data
Resolve the selection asynchronously
Given that you have a Future
on your hand you could either send your message in the onComplete
or use pipeTo
to send the resolved ref back to the yourself:
send on resolution
def receive = {
case data:Data =>
context.actorSelection("akka://Post/user/John").resolveOne(3 seconds)
.onComplete {
case Success(reader) => reader ! data
case Failure(e) => // handle failure
}
}
pipe to self
case class Deferred(data: Data, ref: ActorRef)
var johnRef: Option[ActorRef] = None
def receive = {
case data:Data => johnRef match {
case Some(reader) => reader ! data
case None => context.actorSelection("akka://Post/user/John")
.resolveOne(3 seconds)
.map( reader => Deferred(data,reader)
.pipeTo(self)
case Deferred(data,ref) =>
johnRef = Some(ref)
ref ! data
}
Upvotes: 2