How to send a message to an Akka Actor and wait for a reply

This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 13.10, “How to send a message to an Akka Actor and wait for a reply.”

Problem

You have one actor in a Scala application that needs to ask another actor for some information, and needs an immediate reply. (The first actor can’t continue without the information from the second actor.)

Solution

Use the ? or ask methods to send a message to an Akka actor and wait for a reply, as demonstrated in the following example:

import akka.actor._
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.{Await, ExecutionContext, Future}
import scala.concurrent.duration._
import scala.language.postfixOps

case object AskNameMessage

class TestActor extends Actor {
    def receive = {
        case AskNameMessage => // respond to the 'ask' request
                               sender ! "Fred"
        case _ => println("that was unexpected")
    }
}

object AskTest extends App {

    // create the system and actor
    val system = ActorSystem("AskTestSystem")
    val myActor = system.actorOf(Props[TestActor], name = "myActor")

    // (1) this is one way to "ask" another actor for information
    implicit val timeout = Timeout(5 seconds)
    val future = myActor ? AskNameMessage
    val result = Await.result(future, timeout.duration).asInstanceOf[String]
    println(result)

    // (2) a slightly different way to ask another actor for information
    val future2: Future[String] = ask(myActor, AskNameMessage).mapTo[String]
    val result2 = Await.result(future2, 1 second)
    println(result2)

    system.shutdown
}

Discussion

Both the ? or ask methods use the Future and Await.result approach demonstrated in Recipe 13.9, “Simple Concurrency with Futures”. The recipe is:

  1. Send a message to an actor using either ? or ask instead of the usual ! method.
  2. The ? and ask methods create a Future, so you use Await.result to wait for the response from the other actor.
  3. The actor that’s called should send a reply back using the ! method, as shown in the example, where the TestActor receives the AskNameMessage and returns an answer using sender ! "Fred".

To keep the previous example simple, only one actor is shown, but the same approach is used by two actors. Just use the ? or ask method in your actor, like this:

class FooActor extends Actor {
    def receive = {
        case GetName =>
             val future: Future[String] = ask(otherActor, AskNameMessage).mapTo[String]
             val result = Await.result(future, 1 second)
        case _ => // handle other messages
    }
}

Be careful when writing code that waits for immediate responses like this. This causes your actor to block, which means that it can’t respond to anything else while it’s in this state. When you need to perform work like this, the mantra is, “Delegate, delegate, delegate.”