Akka-Typed has been described as production ready with the release of Akka 2.5.22 so it’s worth exploring what the move to Typed will mean for the interaction patterns we’re used to. There are many new ways of working with Actors in Typed. Here we’ll focus on the major differences around how ActorSystem and an Actor are represented in Typed.
Key Differences
All New APIs
The first thing to remember is that everything is different in Akka-Typed, with all new dependencies and packages. This covers the range from core Actor APIs through to supervision, remoting, clustering, persistence and more. Many of the familiar classes are now generic, some are gone altogether and some new ones have put in an appearance. Inter-operability with a non-typed actor system is possible via but, as with Java’s Collections, the major benefits will come with migrating 100% to Typed, and thus akka.actor.ActorSystem.akka.actor.typed.ActorSystem
No More Actors
Perhaps the most obvious difference is that there’s no more Actor in Akka-Typed. In fairness, the distinction between Actorand ActorRefwas always confusing so having a clearer distinction between the building blocks of an Actor and a reference to and Actor can only be a good thing.
The key new type then is a akka.actor.typed.Behavior[T]. A Behavior is basically a receiver for a message, of type T. On receipt of a message a behavior performs whatever action needs to happen and returns a new Behavior which the Actor switches to (aka ‘become’s in old money). A Behavior can be either a total or a partial function over T, with glue classes existing to help define new behaviors (Behaviors.receive, Behaviors.receiveMsg, Behaviors.receivePartial, …) and to return next states (Behaviors.same, Behaviors.unhandled, …). The new API is quite functional but also covers allows for an object-oriented approach via AbstractBehavior[T]. By explicitly returning a new behavior the model more cleanly supports the implementation of a state machine pattern, as well as the use of immutable patterns for managing mutable state.
In the Typed world, an Actor is created (aka ‘spawn’ed) from an ActorSystemby specifying a Behaviorand possibly also giving it a name. The Actor itself is never really visible to either the caller, who interacts with an ActorRef, or the implementer who only deals with Behavior.
ActorSystem Is An Actor
The new akka.actor.typed.ActorSystem[T]is itself an Actor. This can be a bit of a head-melter at first but at its heart the idea is that the ActorSystem can be the first actor you interact with from *outside* the Actor system and that interactions proceed from there via message passing to other Actors which are contained within that single system. It’s still possible to locate an Actor within the system and send a message to it but the easier pattern of interaction is to go via the ActorSystem.
Props is Gone
There are no more props methods to create, but they’ve been replaced by a different kind of factory – a behavior factory which returns a Behavior.
Interactions
Sending A Message
Once you have an akka.actor.typed.ActorRef[T]it’s quite easy to send a message to it. Let’s say I have a Play Controller class, which has a reference to a SomeActor[Command]
final class SomeController(myActorRef: ActorRef[SomeActor.Command], cc: ControllerComponents)(implicit timeout: Timeout, scheduler: Scheduler, ec: ExecutionContext) extends AbstractController(cc) {
override def someEntryPoint = Action(parse.json) { request =>
myActorRef ! SomeActor.FirstCommand(request)
Response.ACCEPTED
}
}
final class SomeActor extends AbstractBehavior[SomeActor.Command] {
override def onMessage(msg: SomeActor.Command): Behavior[SomeActor.Command] = {
msg match {
case authorizationRequest: SomeActor.AuthorizeCardPayment =>
// Do Stuff Here
Behaviors.same
}
}
}
object AuthorizationRequest {
def behavior: Behavior[Command] = Behaviors.setup(new AuthorizationRequest)
sealed trait Command
case class FirstCommand(requestData: JsValue) extends Command
}
What we have here then is a sealed trait (Command) which acts as the protocol description for the actor. The behavior method is used to initialise the actor based on a factory which is able to construct a new Behavior within a given context. The Controller receives a HTTP request, deserialises it as a JSON entity, and fires it into the actor.
See part 2 on how to receive a response and the Ask pattern.