ByteBat
ByteBat

Reputation: 407

Akka 2.6 Actor Discovery In A Non-Actor Class (Get ActorRef Outside ActorSystem)

I am working with Akka at the moment I have the following protocol.

enter image description here

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

Answers (1)

Levi Ramsey
Levi Ramsey

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

Related Questions