#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. Я отредактирую ответ…