avatar

Andres Jaimes

Akka Actors

By Andres Jaimes

- 3 minutes read - 440 words

The Play Framework is built upon Akka actors, but does everything so that you don’t really need to use them. Despite this, actors are easy to integrate with Play, precisely because it is built on them (there is already an actor system for you to use)

A few exceptions are:

  • websockets handling (doing that using actors is a breeze)
  • scheduling tasks for doing daily or weekly jobs

Akka actors use messages to communicate between among them. This behavior allows callers to send a message and go back to the pool of available threads to keep processing more requests.

A caller usually sends a message and does not expect a response. This is called a tell operation or !. However, web operations usually expect a response from actors that can be used to respond to the user who started the call. This is called an ask operation or ?.

A simple actor can look like this:

 1package actors
 2
 3import akka.actor._
 4
 5object HelloActor {
 6  def props = Props[HelloActor]
 7
 8  case class SayHello(name: String)
 9}
10
11class HelloActor extends Actor {
12  import HelloActor._
13
14  def receive = {
15    case SayHello(name: String) =>
16      sender() ! "Hello, " + name
17  }
18}

And a simple controller that uses our actor would look like this:

 1package controllers
 2
 3import actors.HelloActor
 4import akka.actor.ActorSystem
 5import akka.util.Timeout
 6import javax.inject._
 7import play.api._
 8import play.api.mvc._
 9
10@Singleton
11class HomeController @Inject()(system: ActorSystem, val controllerComponents: ControllerComponents) extends BaseController {
12
13  val helloActor = system.actorOf(HelloActor.props, "hello-actor")
14  
15  import scala.concurrent.duration._
16  import akka.pattern.ask
17  implicit val timeout: Timeout = 5.seconds
18  import scala.concurrent.ExecutionContext.Implicits.global
19
20  def sayHello(name: String) = Action.async {
21    (helloActor ? HelloActor.SayHello(name)).mapTo[String].map { message =>
22      Ok(message)
23    }
24  }
25}

This controller reads a parameter from the path and sends it to the actor. Which in return will respond with a Hello message. Such a message is going to be sent back to our user.

Some important things to notice:

  • We’re using the ? ask operator on our controller, indicating that we expect a response from our actor.
  • We’re using the ! operator (tell) on our actor code to respond back to our controller.
  • Notice how the actor call returns a future. Hence we have to use Action.async on our controller function.

Finally an entry to the conf/routes file has to be added so we can read a name from the path.

GET     /say-hello/:name            controllers.HomeController.sayHello(name: String)

References