Mastering the Receiver Pattern in Akka Typed Actors
- Published on
Mastering the Receiver Pattern in Akka Typed Actors
Akka Typed is a powerful toolkit for building concurrent and distributed systems in Java and Scala. It brings an innovative way to manage state and behavior using Actors, encapsulating the sender-receiver communication model efficiently. In this blog post, we will delve deep into the Receiver Pattern within Akka Typed, exploring its importance, functionality, and how you can implement it in Java.
What is the Receiver Pattern?
The Receiver Pattern in Akka Typed actors is a design strategy that promotes immutability and messages processing through predefined state transitions. By using this pattern, actors can handle incoming messages and maintain state in a clear and organized manner. The concept is built around the idea that an actor can change its behavior dynamically through messages, enabling great flexibility in interactions.
Why Use the Receiver Pattern?
- Encapsulation of State: The Receiver Pattern allows actors to manage their state privately, thus preventing accidental modifications from outside sources.
- Clear Design: It establishes a clear structure for handling various events. Each state transition can be encapsulated in a dedicated behavior.
- Dynamic Behavior: Actors can define new behaviors based on incoming messages effectively, making the system adaptive.
Setting Up Akka Typed in Your Java Project
Before we dive into the Receiver Pattern, let’s ensure you have Akka Typed set up in your project. You can use Gradle or Maven. Here is how you can do it with Maven:
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-actor-typed_2.13</artifactId>
<version>2.6.19</version> <!-- Update to the latest version -->
</dependency>
Implementing the Receiver Pattern
Let’s create a simple actor that models a light switch. The light switch can be in either an "on" or "off" state. Depending on the received messages, it switches between these states.
Step 1: Create the Messages
We first need to define the messages our actor will handle.
public sealed interface LightMessage permits TurnOn, TurnOff {
}
public final class TurnOn implements LightMessage {
}
public final class TurnOff implements LightMessage {
}
Here, the LightMessage
interface defines the command structure. It uses Java’s sealed interfaces to restrict subclasses, ensuring all possible messages are defined.
Step 2: Define the Actor Behavior
The next step involves creating the actor’s behavior. We will define two behaviors: one for when the light is off and another for when it's on.
import akka.actor.typed.Behavior;
import akka.actor.typed.javadsl.AbstractBehavior;
import akka.actor.typed.javadsl.Behaviors;
public class LightSwitch extends AbstractBehavior<LightMessage> {
private LightSwitch(ActorContext<LightMessage> context) {
super(context);
}
public static Behavior<LightMessage> create() {
return Behaviors.setup(LightSwitch::new);
}
@Override
public Receive<LightMessage> createReceive() {
return newReceiveBuilder()
.onMessage(TurnOn.class, this::onTurnOn)
.onMessage(TurnOff.class, this::onTurnOff)
.build();
}
private Behavior<LightMessage> onTurnOn(TurnOn message) {
System.out.println("Light is ON");
return Behaviors.same(); // The behavior remains the same
}
private Behavior<LightMessage> onTurnOff(TurnOff message) {
System.out.println("Light is OFF");
return Behaviors.same(); // The behavior remains the same
}
}
Explanation of the Code
- Abstract Behavior: We extend
AbstractBehavior<LightMessage>
which will manage message processing for our actor. - Static Create Method: This sets up the actor instance.
- Creating Receive: The
createReceive
method specifies how the actor should respond to incoming messages. - Message Handlers: The
onTurnOn
andonTurnOff
methods handle respective messages and print the light status.
Step 3: Running the Actor
To interact with our newly created actor, you need an actor system. Below is how you can create the actor and send messages.
import akka.actor.typed.ActorRef;
import akka.actor.typed.ActorSystem;
public class Main {
public static void main(String[] args) {
ActorSystem<LightMessage> actorSystem = ActorSystem.create(LightSwitch.create(), "LightSystem");
ActorRef<LightMessage> lightSwitchRef = actorSystem;
lightSwitchRef.tell(new TurnOn());
lightSwitchRef.tell(new TurnOff());
// Shutdown the actor system gracefully
actorSystem.terminate();
}
}
Explanation of the Code
- Actor System: We create an
ActorSystem
that will manage lifecycle and supervision for our actor. - Sending Messages: We use the
tell
method to sendTurnOn
andTurnOff
messages to thelightSwitch
. - Terminate System: Finally, we ensure a clean shutdown of the actor system.
The Last Word
The Receiver Pattern in Akka Typed Actors is a valuable design practice that streamlines state management and makes your systems more robust. The pattern allows actors to maintain internal logic neatly while promoting immutability and clear message handling strategies.
By adapting the Receiver Pattern in your projects, you gain increased flexibility, safety, and clarity in your actor-based solutions. For more in-depth information, here are some useful resources:
- Official Akka Typed Documentation
- Introduction to Akka Actors
- Sealed Classes and Interfaces
Feel free to implement and experiment with the Receiver Pattern in your projects. Happy coding!
Checkout our other articles