I am using akka for some time. I started to see some patterns in my code to solve late reply for async io. Is this implementation ok? There is another way to do a late reply without block?
class ApplicationApi(asyncIo : ActorRef) extends Actor {
// store senders to late reply
val waiting = Map[request, ActorRef]()
def receive = {
// an actore request for a user, store it to late reply and ask for asyncIo actor to do the real job
case request : GetUser =>
waiting += (sender -> request)
asyncIo ! AsyncGet("http://app/user/" + request.userId)
// asyncio response, parse and reply
case response : AsyncResponse =>
val user = parseUser(response.body)
waiting.remove(response.request) match {
case Some(actor) => actor ! GetUserResponse(user)
}
}
}
One way to avoid blocking while waiting for a reply is to send using the ask
method—a.k.a. ?
operator—which returns a Future
(unlike !
which returns ()
).
Using the onSuccess
or foreach
methods, you can specify actions to be performed if/when the future is completed with a reply. To use this you need to mix in the AskSupport
trait:
class ApplicationApi(asyncIo : ActorRef) extends Actor with AskSupport {
def receive = {
case request: GetUser =>
val replyTo = sender
asyncIo ? AsyncGet("http://app/user/" + request.userId) onSuccess {
case response: AsyncResponse =>
val user = parseUser(response.body)
replyTo ! GetUserResponse(user)
}
}
Avoid using this technique to perform any side effect that modifies the state of the ApplicationApi
actor, because the effect will happen out-of-sync with the receive loop. Forwarding messages to other actors should be safe, though.
By the way, here is a trick to capture the current sender
as part of the pattern match, avoiding the need to assign it to a variable later.
trait FromSupport { this: Actor =>
case object from {
def unapply(msg: Any) = Some(msg, sender)
}
}
class MyActor extends Actor with FromSupport {
def receive = {
case (request: GetUser) from sender =>
// sender is now a variable (shadowing the method) that is safe to use in a closure
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With