Coexistence
Dependency
The Akka dependencies are available from Akka’s library repository. To access them there, you need to configure the URL for this repository.
To use Akka Actor Typed, you must add the following dependency in your project:
- sbt
val AkkaVersion = "2.10.2" libraryDependencies += "com.typesafe.akka" %% "akka-actor-typed" % AkkaVersion
- Maven
- Gradle
Introduction
We believe Akka Typed will be adopted in existing systems gradually and therefore it’s important to be able to use typed and classic actors together, within the same ActorSystem
. Also, we will not be able to integrate with all existing modules in one big bang release and that is another reason for why these two ways of writing actors must be able to coexist.
There are two different ActorSystem
s: akka.actor.ActorSystem
and akka.actor.typed.ActorSystem
.
Currently the typed actor system is implemented using the classic actor system under the hood. This may change in the future.
Typed and classic can interact the following ways:
- classic actor systems can create typed actors
- typed actors can send messages to classic actors, and opposite
- spawn and supervise typed child from classic parent, and opposite
- watch typed from classic, and opposite
- classic actor system can be converted to a typed actor system
The examples use fully qualified class names for the classic classes to distinguish between typed and classic classes with the same name.
Classic to typed
While coexisting your application will likely still have a classic ActorSystem. This can be converted to a typed ActorSystem so that new code and migrated parts don’t rely on the classic system:
- Scala
- Java
-
source
// In java use the static methods on Adapter to convert from typed to classic import akka.actor.typed.javadsl.Adapter; akka.actor.ActorSystem classicActorSystem = akka.actor.ActorSystem.create(); ActorSystem<Void> typedActorSystem = Adapter.toTyped(classicActorSystem);
Then for new typed actors here’s how you create, watch and send messages to it from a classic actor.
- Scala
- Java
-
source
public abstract static class Typed { interface Command {} public static class Ping implements Command { public final akka.actor.typed.ActorRef<Pong> replyTo; public Ping(ActorRef<Pong> replyTo) { this.replyTo = replyTo; } } public static class Pong {} public static Behavior<Command> behavior() { return Behaviors.receive(Typed.Command.class) .onMessage( Typed.Ping.class, message -> { message.replyTo.tell(new Pong()); return same(); }) .build(); } }
The top level classic actor is created in the usual way:
- Scala
- Java
-
source
akka.actor.ActorSystem as = akka.actor.ActorSystem.create(); akka.actor.ActorRef classic = as.actorOf(Classic.props());
Then it can create a typed actor, watch it, and send a message to it:
- Scala
- Java
-
source
public static class Classic extends AbstractActor { public static akka.actor.Props props() { return akka.actor.Props.create(Classic.class); } private final akka.actor.typed.ActorRef<Typed.Command> second = Adapter.spawn(getContext(), Typed.behavior(), "second"); @Override public void preStart() { Adapter.watch(getContext(), second); second.tell(new Typed.Ping(Adapter.toTyped(getSelf()))); } @Override public Receive createReceive() { return receiveBuilder() .match( Typed.Pong.class, message -> { Adapter.stop(getContext(), second); }) .match( akka.actor.Terminated.class, t -> { getContext().stop(getSelf()); }) .build(); } }
We import the Adapter class and call static methods for conversion.
- Scala
- Java
-
source
// In java use the static methods on Adapter to convert from typed to classic import akka.actor.typed.javadsl.Adapter;
To convert between typed and classic ActorSystem
, ActorContext
and ActorRef
in both directions there are adapter methods in akka.actor.typed.javadsl.Adapter
. Note the inline comments in the example above.
This method of using a top level classic actor is the suggested path for this type of co-existence. However, if you prefer to start with a typed top level actor then you can use the Adapter.spawn
directly from the typed system:
- Scala
- Java
-
source
ActorSystem as = ActorSystem.create(); ActorRef<Typed.Command> typed = Adapter.spawn(as, Typed.create(), "Typed");
The above classic-typed difference is further elaborated in the ActorSystem
section of “Learning Akka Typed from Classic”.
Typed to classic
Let’s turn the example upside down and first start the typed actor and then the classic as a child.
The following will show how to create, watch and send messages back and forth from a typed actor to this classic actor:
- Scala
- Java
-
source
public static class Classic extends AbstractActor { public static akka.actor.Props props() { return akka.actor.Props.create(Classic.class); } @Override public Receive createReceive() { return receiveBuilder().match(Typed.Ping.class, this::onPing).build(); } private void onPing(Typed.Ping message) { message.replyTo.tell(Typed.Pong.INSTANCE); } }
Creating the actor system and the typed actor:
- Scala
- Java
-
source
ActorSystem as = ActorSystem.create(); ActorRef<Typed.Command> typed = Adapter.spawn(as, Typed.create(), "Typed");
Then the typed actor creates the classic actor, watches it and sends and receives a response:
- Scala
- Java
-
source
public static class Typed extends AbstractBehavior<Typed.Command> { public static class Ping { public final akka.actor.typed.ActorRef<Pong> replyTo; public Ping(ActorRef<Pong> replyTo) { this.replyTo = replyTo; } } interface Command {} public enum Pong implements Command { INSTANCE } private final akka.actor.ActorRef second; private Typed(ActorContext<Command> context, akka.actor.ActorRef second) { super(context); this.second = second; } public static Behavior<Command> create() { return akka.actor.typed.javadsl.Behaviors.setup( context -> { akka.actor.ActorRef second = Adapter.actorOf(context, Classic.props(), "second"); Adapter.watch(context, second); second.tell( new Typed.Ping(context.getSelf().narrow()), Adapter.toClassic(context.getSelf())); return new Typed(context, second); }); } @Override public Receive<Command> createReceive() { return newReceiveBuilder() .onMessage(Typed.Pong.class, message -> onPong()) .onSignal(akka.actor.typed.Terminated.class, sig -> Behaviors.stopped()) .build(); } private Behavior<Command> onPong() { Adapter.stop(getContext(), second); return this; } }
Supervision
The default supervision for classic actors is to restart whereas for typed it is to stop. When combining classic and typed actors the default supervision is based on the default behavior of the child, for example if a classic actor creates a typed child, its default supervision will be to stop. If a typed actor creates a classic child, its default supervision will be to restart.