Reputation: 1203
I'm porting an existing application from Akka Classic to Akka Typed. Originally you could obtain a reference to an actor using context.actorSelection().resolveOne()
I understand that in Akka Typed this is no longer supported, and that we should be using Receptionist
to register actors for discovery by ServiceKey
.
However I would like to send messages to a local actor only, a local singleton which is present on every node in the cluster. I had a local path for it but do not have the direct reference to it. This is because it is a health check actor created by the Akka Management system.
From the documentation it appears that registering an actor with the Receptionist
for a ServiceKey makes it available to all members of the cluster. Therefore I will receive references to the singleton actors on all nodes if I query for that ServiceKey
.
There doesn't seem to be a way to register with the Receptionist
only locally, and having these internal refs published out across the cluster seems unnecessarily leaky and violates encapsulation.
It also doesn't seem easy to work out which ref is the local actor from the Listing
returned from the Receptionist
.
I suppose the ServiceKey
used to register could be system specific?
Am I missing an obvious solution here?
Upvotes: 0
Views: 895
Reputation: 20611
In the particular case of Akka Management actors, because that project does not depend on Akka Typed (thus the actor involved is a Classic actor), you can treat your Typed ActorContext
as a Classic ActorContext
and use the ActorSelection
.
From your question, I'm guessing Java (in Scala, implicits make this a little less verbose and perhaps clarify intent):
akka.actor.typed.javadsl.Adapter.toClassic(context).actorSelection(path).resolveOne(timeout)
For the case where one wants to resolve only a Typed local actor, the most effective strategy I've found is to incorporate the resolution functionality into the behavior provided when creating the ActorSystem
. The actor which wants to be found will register with the ActorSystem
and other actors can ask the ActorSystem
for the ActorRef
.
One subtlety here is that context.getSystem()
gives you an ActorSystem<Void>
which extends ActorRef<Void>
. You can get around this by calling unsafeUpcast
on the ActorSystem
, e.g.
// Might not actually be syntactically valid Java, but hopefully the fix to make it
// legal is obvious...
ActorRef<MyActorSystemCommand> systemRef = context.getSystem().unsafeUpcast<MyActorSystemCommand>()
Note that it's pretty important to get the type of messages for the ActorSystem
correct: if the ActorSystem
's behavior doesn't accept that type of message, the actor system will crash (as far as I know, there's no way to prevent the actor system from shutting down) when you send a message.
An evolution of this approach is to define a local-only receptionist actor which is spawned at ActorSystem
startup: actors which wish to interact with this receptionist obtain its ActorRef
through the above method and then that actor handles resolution.
Note of course, that in both of these approaches (as with the cluster-aware Receptionist
), only actors which explicitly opt-in to being resolved like this are resolvable. This is in keeping with an underlying theme of Akka Typed: putting the actor more in charge of how much it exposes to the outside world.
Upvotes: 1