Акка Pattern - Актер дерево, ответ на исходный источник

Это вопрос дизайна;

Скажем, у меня есть дерево актеров, которые выполняют кучу обработки. Обработка запускается клиентом/партнером по подключению (т.е. Дерево является сервером). В конце концов, клиент-клиент хочет получить ответ. То есть У меня есть актерская система, которая выглядит так.

    ActorA  <---reqData--- Client_Actor
       | msgA                    /|\                      
      \|/                         |                 
    ActorB                        |                  
  msgB |  \ msgD                  | 
      \|/  \/                     | 
    ActorC  ActorD---------msgY-->|
       |_____________msgX_________|

Ответ, который хочет клиентская система, - это выход из актеров листа (т.е. ActorC и/или ActorD). Эти актеры в дереве могут взаимодействовать с внешними системами. Это дерево может быть набором заранее определенных, возможно, маршрутизируемых актеров (т.е. Поэтому Client_actor имеет только actorref для корня дерева актеров, ActorA).

Вопрос заключается в том, что является лучшим шаблоном для управления отправкой ответа (msgX &/или msgY) от участников финала/листа обратно к клиенту-актеру?

Я могу вспомнить следующие варианты:

  • Создайте дерево для каждого клиента подключения и попросите участников отслеживать отправителя, когда они получат msgX или msgY, отправьте его обратно исходному отправителю, чтобы сообщения передавались обратно через дерево. I. Каждый актер будет держать ссылку исходного отправителя.
  • Каким-то образом отправьте сообщение Client_actor ref в сообщении reqData и скопируйте его для всех сообщений, используемых в дереве, чтобы субъекты листа могли напрямую ответить на Client_actor... Это похоже на самый эффективный вариант. Не уверен, как это сделать (я как-то думаю о чертах в классах сообщений, в которых присутствует клиентский агент ref)...
  • Как-то найти клиент-клиент на основе уникального идентификатора в сообщениях, переданных через дерево или использовать actorselection (не уверен, насколько хорошо это будет работать с удалением)...
  • Что-то лучше...

FYI Я использую Akka 2.2.1.

Ура!

Ответ 1

Вы можете использовать метод forward для пересылки сообщения от исходного отправителя дочернему отправителю на каждом уровне.

в Client_Actor:

actorA ! "hello"

в ActorA:

def receive = {
  case msg =>
    ???
    actorB forward msg
}

в ActorB:

def receive = {
  case msg =>
    ???
    actorC forward msg
}

в ActorC:

def receive = {
  case msg =>
    ???
    sender ! "reply" // sender is Client_Actor!
}

В этом случае поле "отправитель" сообщения никогда не изменится, поэтому ActorC ответит на оригинальный Client_Actor!

Вы можете продолжить это, используя вариант метода tell, который позволяет указать отправителя:

destinationActor.tell("my message", someSenderActor);

Ответ 2

Самый простой способ - отправить сообщения с ref на источник Client_Actor

Client
 sendMsg(Client to, Client resultTo)

Client_Actor
 req_data(Client to){
   sendMsg(to, this);
 }

Это хороший вариант, если вы не знаете, какой клиент имеет результат для оригинального плаката, а какой нет.

Если вы это знаете, а Client_Actor - только один (например, у нас есть дерево, и эти и только LEAFS всегда будут реагировать только на Client_Actor), вы можете сделать что-то вроде этого:

Client
  register_actor(Client actor){this.actor = actor;}
  call_actor(){ this.actor.sendMsg(); }

Ответ 3

В таких ситуациях я написал что-то, называемое ResponseAggregator. Это экземпляр Actor, созданный по мере необходимости (а не как постоянный единичный экземпляр), принимающий в качестве аргументов пункт назначения ActorRef, произвольный key (чтобы отличить агрегатор, если один получатель получает больше одного агрегатора) предикат завершения, который принимает ответы Seq[Any], полученные агентом, и который возвращает true, если эти ответы представляют собой завершение процесса агрегации и значения тайм-аута. Агрегатор принимает и собирает входящие сообщения, пока предикат не вернет true или истечет время ожидания. Как только агрегация завершена (в том числе из-за таймаута), все отправленные сообщения отправляются в пункт назначения вместе с флагом, указывающим, было ли время ожидания агрегации.

Код слишком велик, чтобы включить сюда и не является открытым исходным кодом.

Чтобы это работало, сообщения, распространяющиеся через систему, должны иметь ActorRef, указывающие, кому нужно отправить ответное сообщение (я редко создаю актеров, которые отвечают только на sender).

Я часто определяю поле replyTo значения сообщения как ActorRef*, а затем использую класс MulticastActor, который позволяет оператору !* отправить нескольким получателям. Это имеет преимущество синтаксической чистоты в построении сообщений (по сравнению с использованием Option [ActorRef] или Seq [ActorRef]) и имеет равные накладные расходы (требующие построения чего-либо для захвата ответа-ответа актера или refs).

В любом случае, с помощью этих вещей вы можете настроить довольно гибкие топологии маршрутизации.