Reputation: 407
I am working with Akka at the moment I have the following protocol.
In my protocol I have a server that is only responsible for creating resources (room and gabblers). These resources are created and then accessed. Next, I would like by means of a key to find the corresponding Gabbler ActorRef to send a message but this time from a class that exposes an API / method that is not an actor. I have seen the documentation and it is incredible to me that there is not a method in the actor system that can return a specific actor from its hierarchy to use it. I have already read the Receptionist section and although it is not very clear to me, I see that it is again oriented to the actors. There is no method in Akka that returns the reference based on the path of the Actor?
package co.test;
import akka.actor.typed.ActorSystem;
import akka.actor.typed.javadsl.AskPattern;
import akka.actor.typed.receptionist.Receptionist;
import co.test.actors.ChatServer;
public class ChatServerApplication {
public static void main(String[] args) {
ActorSystem<ChatServer.ServerCommand> system =
ActorSystem.create(ChatServer.create(), "chat-server");
system.tell(new ChatServer.NewEventRoom("room1"));
system.tell(new ChatServer.AttendeeJoin("room1", "user1"));
system.tell(new ChatServer.AttendeeJoin("room1", "user2"));
system.tell(new ChatServer.AttendeeJoin("room1", "user3"));
system.tell(new ChatServer.AttendeeJoin("room1", "user4"));
system.tell(new ChatServer.AttendeeJoin("room1", "user5"));
system.tell(new ChatServer.AttendeeJoin("room1", "user6"));
system.tell(new ChatServer.AttendeeJoin("room1", "user7"));
//ActorRef<Gabbler.Command> gabbler = get specific Gabbler ActorRef
//gabbler.tell(new Gabbler.SendMessage("test");
}
}
The protocol in the image above is already implemented but I am stuck in understanding what was asked above.
Upvotes: 0
Views: 394
Reputation: 20611
In general, for getting data from actors to outside of the actor system (e.g. the main
method), you're dealing with the ask pattern. When using the ask pattern, you'll need to design your message protocol to support it, typically by having messages that are intended to be asked having an ActorRef<ReplyMsg>
field (often named replyTo
). akka.actor.typed.javadsl.AskPattern.ask
effectively creates a short-lived actor, injects the ActorRef
of that actor into the message, and if it gets a message within a timeout period, it completes a CompletionStage
with that message.
In this application, since you're routing everything from main
through the system
actor, you could define a ChatServer.GetAttendee
message:
// assuming that there's an interface Command {} already in ChatServer
public class ChatServer extends AbstractBehavior<ChatServer.Command> {
public static class GetAttendee extends Command {
public final String room;
public final String user;
public final ActorRef<ChatServer.AttendeeIs> replyTo;
public GetAttendee(String room, String user, ActorRef<ChatServer.AttendeeIs> replyTo) {
this.room = room;
this.user = user;
this.replyTo = replyTo;
}
}
public static class AttendeeIs {
public final ActorRef<Gabbler.Command> ref
public AttendeeIs(ActorRef<Gabbler.Command> ref) {
this.ref = ref;
}
}
}
(the ChatServer
would likely pass the message on the corresponding ChatRoom
)
In your main
, you would send the ask with something like
String desiredRoom = "whatever";
String desiredUser = "whoever";
CompletionStage<ChatServer.AttendeeIs> getGabbler =
AskPattern.ask(
system,
replyTo -> new ChatServer.GetAttendee(desiredRoom, desiredUser, replyTo),
Duration.ofSeconds(15),
system.scheduler()
)
CompletionStage<ActorRef<Gabbler.Command>> gabblerFuture =
getGabbler.thenCompose(
(ChatServer.AttendeeIs response) ->
return CompletableFuture.completedFuture(response.ref)
)
ActorRef<Gabbler.Command> gabbler = gabblerFuture.toCompletableFuture().get()
Upvotes: 2