Отправителя внутри будущего

У меня есть актер, который при получении сообщения ищет файловую систему для файла и возвращает полный путь к файлу.

Чтобы сохранить его асинхронным, я сделал:

def receive ={
case s:String => {

  val f = future{
      val ans = search(s)
      println("Input Request: "+s+" output:"+ans+" "+sender.path)
  }
  f.onComplete{
    case Success(x) => sender ! x
    case Failure(y) => println("Could not complete it")
  } 

}

Но я заметил, что он возвращает сообщение akka://FileSystem/deadLetters, а не sender. Документация гласит, что:

Действует только в самом Актере, поэтому не закрывайте его и    * публиковать его в других потоках!

Так значит ли это, мне придется обязательно поддерживать синхронность? Есть ли другой путь?

Ответы

Ответ 1

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

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

val origSender = sender
f.onComplete {
    case Successs(x) => origSender ! x
    ...
}

Ответ 2

import akka.pattern.pipe

Есть трюк. Выполнение:

val reply = sender
future {
  val ans = searchAndCache(s)
  println("Input Request: "+s+" output:"+ans+" "+reply.path)
  ans
} pipeTo reply

отвечает отправителю