Akka Notes - Actor Messaging - Request and Response - 3
Last time when we saw Actor messaging, we saw how fire-n-forget messages are sent (Meaning, we just send a message to the Actor but don't expect a response from the Actor).
Technically, we fire messages to Actors for its side-effects ALL THE TIME. It is by design. Other than not responding, the target Actor could ALSO do the following with that message -
-
Send a response back to the sender (in our case, the
TeacherActorwould respond with a quote back to theStudentActorOR -
Forward a response back to some other Actor who might be the intended audience which in turn might respond/forward/have a side-effect. Routers and Supervisors are examples of those cases. (we'll look at them very soon)
Request & Response
In this write-up, we'll be focussing only on Point 1 - the request-response cycle.

The picture conveys what we are trying to achieve this time. For sake of brevity, I didn't represent the ActorSystem, Dispatcher or Mailboxes in the picture.
-
The
DriverAppsends anInitSignalmessage to theStudentActor. -
The
StudentActorreacts to theInitSignalmessage and sends aQuoteRequestmessage to theTeacherActor. -
The
TeacherActor, like we saw in the first discussion, responds with aQuoteResponse. -
The
StudentActorjust logs theQuoteResponseto the console/logger.
We'll also cook up a testcase to verify it.
Let's look at these 4 points in detail now :
1. The DriverApp sends an InitSignal message to the StudentActor

By now, you would have guessed what would the DriverApp do. Just 4 things :
- Initialize the
ActorSystem
//Initialize the ActorSystem
val system = ActorSystem("UniversityMessageSystem")
- Create the
TeacherActor
//create the teacher actor
val teacherRef = system.actorOf(Props[TeacherActor], "teacherActor")
- Create the
StudentActor
//create the Student Actor - pass the teacher actorref as a constructor parameter to StudentActor
val studentRef = system.actorOf(Props(new StudentActor(teacherRef)), "studentActor")
You'll notice that I am passing in the ActorRef of the TeacherActor to the constructor of the StudentActor so that the StudentActor could use the ActorRef for sending messages to the TeacherActor. There are other ways to achieve this (like passing in the Props) but this method would come in handy when we look at Supervisors and Routers in the following write-ups. We'll also be looking at child actors pretty soon but that wouldn't semantically be the right approach here - Student creating Teacher doesn't sound nice. Does it?
Lastly,
- The
DriverAppwould then send anInitSignalto theStudentActor, so that the StudentActor could start sending the QuoteRequest message to the TeacherActor.
//send a message to the Student Actor
studentRef ! InitSignal
That's pretty much the DriverClass. The Thread.sleep and the ActorSystem.shutdown are just to wait for a couple of seconds for the message sending to finish before we finally shut down the ActorSystem.
DriverApp.scala
package me.rerun.akkanotes.messaging.requestresponse
import akka.actor.ActorSystem
import akka.actor.Props
import me.rerun.akkanotes.messaging.protocols.StudentProtocol._
import akka.actor.ActorRef
object DriverApp extends App {
//Initialize the ActorSystem
val system = ActorSystem("UniversityMessageSystem")
//construct the teacher actor
val teacherRef = system.actorOf(Props[TeacherActor], "teacherActor")
//construct the Student Actor - pass the teacher actorref as a constructor parameter to StudentActor
val studentRef = system.actorOf(Props(new StudentActor(teacherRef)), "studentActor")
//send a message to the Student Actor
studentRef ! InitSignal
//Let's wait for a couple of seconds before we shut down the system
Thread.sleep(2000)
//Shut down the ActorSystem.
system.shutdown()
}
2. The StudentActor reacts to the InitSignal message and sends a QuoteRequest message to the TeacherActor
AND
4. The StudentActor receives the QuoteResponse from TeacherActor and just logs to the console/logger
Why did I combine Points 2 and 4? Because it is so simple you'll hate me if I separate them.

So, Point 2 - the StudentActor receives the InitSignal message from the DriverApp and sends QuoteRequest to the TeacherActor.
def receive = {
case InitSignal=> {
teacherActorRef!QuoteRequest
}
...
...
That's it !!!
Point 4 - The StudentActor logs the message that it receives from the TeacherActor.

Just, as promised :
case QuoteResponse(quoteString) => {
log.info ("Received QuoteResponse from Teacher")
log.info(s"Printing from Student Actor $quoteString")
}
I am sure you'd agree that it almost looks like pseudocode now.
So, the entire StudentActor class looks like :
StudentActor.scala
package me.rerun.akkanotes.messaging.requestresponse
import akka.actor.Actor
import akka.actor.ActorLogging
import me.rerun.akkanotes.messaging.protocols.TeacherProtocol._
import me.rerun.akkanotes.messaging.protocols.StudentProtocol._
import akka.actor.Props
import akka.actor.ActorRef
class StudentActor (teacherActorRef:ActorRef) extends Actor with ActorLogging {
def receive = {
case InitSignal=> {
teacherActorRef!QuoteRequest
}
case QuoteResponse(quoteString) => {
log.info ("Received QuoteResponse from Teacher")
log.info(s"Printing from Student Actor $quoteString")
}
}
}
3. The TeacherActor responds with a QuoteResponse.
This is the exact same code as we saw in the fire-n-forget write-up.
The TeacherActor receives a QuoteRequest message and sends QuoteResponse back.
TeacherActor.scala
package me.rerun.akkanotes.messaging.requestresponse
import scala.util.Random
import akka.actor.Actor
import akka.actor.ActorLogging
import akka.actor.actorRef2Scala
import me.rerun.akkanotes.messaging.protocols.TeacherProtocol._
class TeacherActor extends Actor with ActorLogging {
val quotes = List(
"Moderation is for cowards",
"Anything worth doing is worth overdoing",
"The trouble is you think you have time",
"You never gonna know if you never even try")
def receive = {
case QuoteRequest => {
import util.Random
//Get a random Quote from the list and construct a response
val quoteResponse = QuoteResponse(quotes(Random.nextInt(quotes.size)))
//respond back to the Student who is the original sender of QuoteRequest
sender ! quoteResponse
}
}
}
Testcases
Now, our testcase would simulate the DriverApp. Since, the StudentActor just logs the message and we won't be able to assert on the QuoteResponse itself, we'll just assert the presence of the log message in the EventStream (just like we talked last time)
So, our testcase looks like :
"A student" must {
"log a QuoteResponse eventually when an InitSignal is sent to it" in {
import me.rerun.akkanotes.messaging.protocols.StudentProtocol._
val teacherRef = system.actorOf(Props[TeacherActor], "teacherActor")
val studentRef = system.actorOf(Props(new StudentActor(teacherRef)), "studentActor")
EventFilter.info (start="Printing from Student Actor", occurrences=1).intercept{
studentRef!InitSignal
}
}
}
Code
The entire project could be downloaded from github here.
Next up, we'll see how to use schedulers in Akka and monitoring your Akka app using Kamon