I want to do something like this -
class MyActor extends Actor {
....
override def receive = {
case msg =>
.... // do something
Future {
... // calculate response
sender ! response
}
}
}
// in some other code -
val future = myActorRef ? msg
future.onSuccess {
....
}
Would this work? In other words, does Akka's "ask" implementation care if the response was sent back before the "receive" method finishes or not?
Yes it would work, and there is even a built-in akka pattern for it - pipe
:
import akka.pattern.pipe
override def receive = {
case msg =>
.... // do something
Future {
... // calculate response
response
} pipeTo sender()
}
There are, however some caveats in your code you should note:
sender
is a function, therefore, when the code inside your Future{...}
block executes, the actor may be handling a message from another sender, so you may reply to the wrong sender. To avoid this, evaluate your sender outside the closure:
val mySender = sender()
Future {
... // calculate response
mySender ! response
}
You don't however need to worry about this if you use pipe
.
You are wrapping a future into an actor and calling that actor with ask
, which again gives you a future. You should really consider calling the future directly, without actors.
If you really need the actor, e.g. because you're isolating some mutable state or message ordering is important, you should be aware that computing the Future
will not happen on the actor's thread, so you are losing your state consistency and message ordering - another reason to consider losing the actor, and calling the future directly.