Обнаружение актера Akka 2.6 в классе, не являющемся актером (получение ActorRef вне ActorSystem)

Я работаю с Akka, на данный момент у меня есть следующий протокол.

введите здесь описание изображения

В моем протоколе у ​​меня есть сервер, который отвечает только за создание ресурсов (комнаты и габблеры). Эти ресурсы создаются, а затем доступны. Затем я хотел бы с помощью ключа найти соответствующий Gabbler ActorRef для отправки сообщения, но на этот раз из класса, который предоставляет API/метод, который не является актором. Я видел документацию, и мне кажется невероятным, что в системе акторов нет метода, который может возвращать конкретного актора из его иерархии для его использования. Я уже читал раздел «Ресепшн», и хотя он мне не очень понятен, я вижу, что он опять же ориентирован на актеров. В Akka нет метода, который возвращает ссылку на основе пути Актера?

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");
    }
    
}

Протокол на изображении выше уже реализован, но я застрял в понимании того, что было задано выше.


person BiteBat    schedule 12.01.2021    source источник


Ответы (1)


В общем, для получения данных от акторов за пределы системы акторов (например, метод main) вы имеете дело с шаблон запроса. При использовании шаблона запроса вам необходимо разработать протокол сообщений для его поддержки, обычно с сообщениями, предназначенными для запроса, с полем ActorRef<ReplyMsg> (часто называемым replyTo). akka.actor.typed.javadsl.AskPattern.ask фактически создает недолговечный актор, вводит ActorRef этого актора в сообщение, и если он получает сообщение в течение периода ожидания, он завершает CompletionStage с этим сообщением.

В этом приложении, поскольку вы маршрутизируете все от main через актера system, вы можете определить сообщение ChatServer.GetAttendee:

// 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;
    }
  }
}

(скорее всего, ChatServer передаст сообщение соответствующему ChatRoom)

В своем main вы бы отправили запрос с чем-то вроде

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()
person Levi Ramsey    schedule 14.01.2021
comment
Большое спасибо, Леви, за ответ. Я понимаю подход к решению моего вопроса. Но я вижу, что шаблон запроса является синхронным, что в конечном итоге препятствует оптимизации асинхронности, предлагаемой шаблоном сообщения. Поскольку я новичок в наборе инструментов Akka, мне было нелегко продвигаться вперед. Я рассматривал две возможности асинхронного решения вопроса: - person BiteBat; 14.01.2021
comment
1. С секретарем я мог бы сгенерировать хэш, в котором можно идентифицировать каждого из габблеров, и через сообщение, включающее их идентификатор, секретарша направит его (я не знаю, насколько это оптимально). 2. Я осознал важность потоков, рассматривая их сейчас как инструмент преимущественно для реактивной работы и рассматривая акторов как ресурсы для ее достижения. Это стоило мне, но мне пришлось бы исследовать гораздо больше, чтобы найти решение. Леви, что вы думаете об этих двух подходах? Или вы думаете, что я должен использовать шаблон запроса? - person BiteBat; 14.01.2021
comment
Наконец, Леви, извини, что так много прошу. При подходе с запросом главный актор (сервер чата) был бы актором обнаружения всех актеров, если бы было слишком много разных актеров, основной был бы очень тяжелым. Вдруг вы знаете, почему если есть уникальный идентификатор акторов типа пути, то нет просто Map и метода, который будет возвращать ссылку на актора? - person BiteBat; 14.01.2021
comment
Ask является синхронным только в той степени, в которой вы блокируете ожидание ответа: то есть вы делаете все возможное в обратных вызовах для фьючерсов. - person Levi Ramsey; 14.01.2021
comment
На практике использование администратора ничем не отличается от маршрутизации сообщений через главного актера. Это вводит точку удушья. - person Levi Ramsey; 14.01.2021
comment
Что касается потоков, скорее всего, вы будете использовать шаблон запроса при взаимодействии с актерами из потока (чтобы иметь обратное давление). - person Levi Ramsey; 14.01.2021
comment
Если бы я разрабатывал это, я бы на самом деле имел NewEventRoom запрос с ответом, содержащим ActorRef<ChatRoom>, а затем отправлял AttendeeJoin сообщения актеру ChatRoom (с поддержкой запроса), но это более существенный редизайн. - person Levi Ramsey; 14.01.2021
comment
Большое спасибо, Леви, я понимаю, что продолжу сначала практиковаться с паттерном аск. - person BiteBat; 14.01.2021