I have an akka actor that is using the classic style based on this TCP connection example: https://doc.akka.io/docs/akka/current/io-tcp.html
I am trying to instantiate this actor from inside of a akka typed application (because I can't find an example of this exact same TCP connection using typed - not sure if the API is available?)
implicit val system = ActorSystem(SomeActor(), "typed-actorSystem") // import akka.actor.typed.ActorSystem
val remote = new InetSocketAddress(config.host, config.port)
val client =
system.classicSystem.actorOf(Client.props(remote), "clientActor")
Error:
) java.lang.UnsupportedOperationException: cannot create top-level actor [clientActor] from the outside on ActorSystem with custom user guardian [error] java.lang.UnsupportedOperationException: cannot create top-level actor [clientActor] from the outside on ActorSystem with custom user guardian
How can I fix this? Do I have to instantiate this actor somewhere else?
You are hitting an impedance mismatch between Akka Classic and Akka Typed.
The general recommendation in the Akka docs for this type of situation is to use a Classic ActorSystem when needing to coexist with classic code. The docs don't spell it out explicitly, but you can then spawn your typed guardian actor's behavior and have all typed actors be a child of that guardian actor, so instead of
// typed: guardianBehavior is a Behavior[T], so system is an ActorSystem[T]
val system = ActorSystem(guardianBehavior, "my-actor-system")
you'd have
import akka.actor.typed.scaladsl.adapter.ClassicActorSystemOps
// A classic actor system
val system = ActorSystem("my-actor-system")
// Typed guardian, will be in the parental chain of all typed actors
val typedGuardian = system.spawn(guardianBehavior, "typed-guardian")
This does preclude your typed actors from sending messages to the guardian via context.system.unsafeUpcast
; other than that, the only operations on ActorSystem[T]
for which T
is meaningful are ones that are using it as an ActorRef[T]
, so those can still use typedGuardian
, you just have to manually thread it through (which is arguably a more reputable thing than doing context.system.unsafeUpcast
...)