Designing Actor Systems
Learn to design and implement actor hierarchies, define actor behaviors, and send/receive messages.
Designing Actor Systems is a free Scala for Backend Engineering & Functional Programming lesson on CoddyKit — lesson 2 of 3. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Scala for Backend Engineering & Functional Programming learning path, one of 3 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Design Actor Systems: Intro
Welcome to Lesson 2! In the previous lesson, we learned the basics of the Akka Actor Model. Now, let's dive into designing Akka Actor Systems.
A well-designed actor system is robust, scalable, and easy to maintain. We'll explore how to structure your actors, define their behaviors, and enable them to communicate effectively.
Understanding Actor Hierarchies
Akka actors are organized in a tree-like hierarchy, much like a file system. Every actor, except the 'root' actor, has a parent.
- Parent-Child Relationship: An actor that creates another actor becomes its parent.
- Supervision: This hierarchy is crucial for Akka's fault tolerance. Parents are responsible for supervising their children (more on this in the next lesson!).
- Path-based Addressing: Each actor has a unique path, reflecting its position in the hierarchy, like
/user/parentActor/childActor.
Setting Up Your ActorSystem
The ActorSystem is the entry point for all Akka applications. It manages the resources needed for actors, including thread pools and schedulers.
You create it once per application and then use it to create your top-level actors. It's like the container for your entire actor application.
Try running this simple code to create an ActorSystem:
import akka.actor.ActorSystem
object AkkaSystemApp {
def main(args: Array[String]): Unit = {
// Create an ActorSystem with a unique name
val system = ActorSystem("MyFirstActorSystem")
println("ActorSystem created: " + system.name)
// Remember to terminate the system when done!
system.terminate()
}
}Defining Actor Behavior
An actor's behavior determines how it reacts to different messages. In Scala, you define this by extending the Actor trait and implementing the receive method.
- The
receivemethod is a partial function that matches incoming messages to specific actions. - Each actor processes messages one by one, sequentially, ensuring thread safety for its internal state.
ActorRef: The Actor's Address
You don't directly interact with actor instances. Instead, you send messages to an ActorRef. Think of ActorRef as a postal address for an actor.
- It's a handle that represents a specific actor within the system.
- Messages sent to an
ActorRefare placed in the actor's mailbox. - You obtain an
ActorRefwhen you create an actor usingactorOf.
Sending Messages to Actors
The primary way actors communicate is by sending messages. The most common way to send a message is using the ! (pronounced 'tell') method.
receiverActorRef ! "Your message here"
The tell method is asynchronous and fire-and-forget. It sends the message and doesn't wait for a reply.
Let's combine creating an actor and sending it messages:
import akka.actor.{Actor, ActorRef, Props, ActorSystem}
// 1. Define the actor's behavior
class GreeterActor extends Actor {
def receive = {
case "hello" => println(s"Greeter: Hello from ${self.path.name}!")
case msg: String => println(s"Greeter: Received message: '$msg'")
case _ => println("Greeter: Received something unexpected!")
}
}
object SimpleActorApp {
def main(args: Array[String]): Unit = {
// 2. Create the ActorSystem
val system = ActorSystem("GreeterSystem")
// 3. Create a top-level actor and get its ActorRef
val greeter: ActorRef = system.actorOf(Props[GreeterActor], "myGreeter")
// 4. Send messages to the actor using '!'
greeter ! "hello"
greeter ! "How are you doing today?"
greeter ! 123 // This will match the _ case
// Give actors time to process messages, then terminate
Thread.sleep(1000)
system.terminate()
}
}Creating Child Actors
Actors can create other actors, forming the hierarchy we discussed. A parent actor creates its child actors using context.actorOf.
context.actorOf: Used by an actor to create its children.system.actorOf: Used by the application to create top-level (guardian) actors.
Creating child actors helps in organizing your system, delegating tasks, and isolating failures.
Parent-Child Communication
Actors communicate by sending messages to each other's ActorRef. A child actor can get its parent's ActorRef via context.parent. To reply to the sender of a message, an actor can use sender().
Let's see an example where a parent creates a child, tells it to do work, and the child reports back when done:
import akka.actor.{Actor, ActorRef, Props, ActorSystem}
import scala.concurrent.ExecutionContext.Implicits.global
// Child Actor Definition: Does work and replies to sender
class ChildActor extends Actor {
def receive = {
case "work" =>
println(s"ChildActor (${self.path.name}): Doing work from ${sender().path.name}")
sender() ! "done" // Reply 'done' to the sender (parent)
}
}
// Parent Actor Definition: Creates child, sends work, receives reply
class ParentActor extends Actor {
// Create a child actor when the parent starts
val child: ActorRef = context.actorOf(Props[ChildActor], "myChild")
def receive = {
case "start" =>
println("ParentActor: Kicking off child's work.")
child ! "work" // Tell the child to do 'work'
case "done" =>
println(s"ParentActor: Child ${sender().path.name} reported 'done'.")
context.stop(child) // Stop the child actor
context.stop(self) // Stop the parent actor
}
}
object HierarchyApp {
def main(args: Array[String]): Unit = {
val system = ActorSystem("HierarchySystem")
val parent: ActorRef = system.actorOf(Props[ParentActor], "parentActor")
parent ! "start" // Start the interaction
// Wait for the system to terminate (actors will stop themselves)
system.whenTerminated.onComplete(_ => println("ActorSystem terminated."))
}
}Stopping Actors Gracefully
Actors should be stopped gracefully when they are no longer needed to release resources. You can stop an actor in a few ways:
context.stop(self): An actor stops itself.context.stop(childRef): A parent stops one of its children.system.stop(actorRef): For top-level actors, though usually, you stop the entire system.
When an actor stops, it processes all messages in its mailbox before terminating. Its children are also stopped recursively.
Quick Check: Actor Design
Consider the following Akka actor code snippet. What is the correct way for MyChildActor to send a message back to its creating parent, MyParentActor, if MyParentActor was the sender of the initial 'request' message?
Recap: Designing Actor Systems
Great job! In this lesson, we've covered key aspects of designing Akka Actor Systems:
- Actors are organized in hierarchies, which are vital for supervision and structure.
- The
ActorSystemis your application's entry point for Akka. - You define actor behavior using the
receivemethod. ActorRefis the address for sending messages.- Actors communicate asynchronously using the
!(tell) method. - Parents create children with
context.actorOf, and children can reply usingsender(). - Actors can be stopped gracefully using
context.stop().
Next, we'll delve deeper into Akka's powerful supervision strategies and how to handle failures gracefully!
Frequently asked questions
Is the “Designing Actor Systems” lesson free?
Yes — the full text of “Designing Actor Systems” is free to read here on the web, and the Scala for Backend Engineering & Functional Programming course includes 3 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Scala for Backend Engineering & Functional Programming course, upgrade to CoddyKit PRO.
What will I learn in “Designing Actor Systems”?
Learn to design and implement actor hierarchies, define actor behaviors, and send/receive messages. You practise Scala for Backend Engineering & Functional Programming with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Scala for Backend Engineering & Functional Programming?
No prior experience is required. Scala for Backend Engineering & Functional Programming on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 3, so you can start here or from the beginning and move at your own pace.
How long does the “Designing Actor Systems” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Scala for Backend Engineering & Functional Programming lesson?
Yes. Every Scala for Backend Engineering & Functional Programming lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Akka Actor Model Fundamentals
- Designing Actor Systems
- Supervision and Fault Tolerance