Получить цель/получателя запроса Akka

#scala #akka

Вопрос:

Я использую следующий фрагмент кода в своем классическом проекте Akka.

 (persistence ? Persist("a", Some(100), 123)) (100.milliseconds)
  .mapTo[Persisted]
  .recover(ex => Failure(ex.getMessage()))
  .pipeTo(self)
 

Когда я обработаю ответ об успешном выполнении этого ask , отправитель будет self . Как я могу получить ответ отправителя на это ask ? Другими словами, как я могу получить адрес получателя/ получателя здесь?

Редактировать:

Совершенно очевидно, что persistence это цель запроса. Но что я действительно хочу знать, так это есть ли способ, чтобы persistence адрес был доступен через pipeTo . Допустим, есть массив, из persistence которого я бы не знал, какое Persist сообщение пришло от какого persistence .

Ответ №1:

Ответ кроется в вашем вопросе. persistence является целью запроса.

Возможно, persistence это делегирование работы другому субъекту (например, работнику в пуле), но это раскрыло бы детали реализации, и tbh, вероятно, не будет таким полезным (что является частью того, почему шаблон ask не распространяется на отправителя).

Если вы управляете протоколом, то явное добавление an ActorRef в ответ гарантированно сработает.

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

РЕДАКТИРОВАТЬ: чтобы persistence перейти к перенаправленному ответу, проще всего map Future преобразовать результат запроса во что-то, что связывается persistence с результатом (как своего рода идентификатор корреляции), например:

 (persistence ? Persist("a", Some(100), 123)) (100.milliseconds)
  .mapTo[Persisted]
  .map { response => persistence -> response }
  .recoverWith { ex => persistence -> Failure(ex.getMessage) }
  .pipeTo(self)
 

Отправляемые сообщения будут состоять из кортежей ActorRef и или Persisted или Failure , поэтому вы сопоставите их в своем получении с чем-то вроде

 case (persistenceTarget, Persisted(...)) => ???
case (persistenceTarget, Failure(msg)) => ???
 

(Вы также можете явно изменить протокол на что-то, что включает в ActorRef себя : кортеж, возможно, немного слишком примитивен, но удобен для этого ответа, не зная более подробной информации о протоколе)

Обратите внимание , что если persistence в вашем поле есть поле Actor , оно может измениться в промежутке между отправкой запроса и выполнением map / recoverWith : map / recoverWith в конечном итоге получит измененное значение. Это непреднамеренное «закрытие» состояния актера является давним источником неприятных ошибок в Акке, поэтому, возможно, стоит иметь

 val persistenceTarget = persistence
 

и заменив упоминания persistence в запросе/ map / recoverWith на persistenceTarget : поскольку persistenceTarget это локальное (и неизменяемое) значение, его можно безопасно закрыть.

Комментарии:

1. Спасибо! В тебе есть здравый смысл. Мне бы очень хотелось, чтобы persistence адрес был возвращен в pipeTo . Потому что, допустим, есть список persistence , и тогда я бы не знал, какое Persist сообщение было отправлено каким persistence .

2. Понял! Я думаю, что я собираюсь создать оболочку вокруг ответа, которая включает адрес и передаст его самому себе. Спасибо за подсказку!

3. Да, вы можете добавить его в map на ask будущем (хотя вам нужно быть осторожным, если persistence есть какой-то актер на уровне государства, и то, что вы получите в процессе обработки, что конкретное сообщение: в первом случае, я бы предложил сохранить в локальной переменной во-первых, в противном случае вы, возможно, пресловутый ковер выдернули из-под тебя)

4. Я отредактирую ответ…