Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sender inside a future

Tags:

I have an actor which on receiving a message, searches the filesystem for a file and returns the full path of the File.

To keep it asynchronous, I have done:

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

But I have observed that it returns the message to akka://FileSystem/deadLetters and not the sender. Documentation says that:

Only valid within the Actor itself, so do not close over it and * publish it to other threads!

So does it mean, I will have to necessarily keep it synchronous? Is there any other way?

like image 538
Jatin Avatar asked Jun 03 '13 13:06

Jatin


2 Answers

You are making a very common mistake of "closing over mutable state". The closure you pass to onComplete does not make a copy of this.sender, so when your onComplete gets called, you are sending the message to whatever this.sender happens to point to at that time, not what it pointed to when you created the closure.

You can avoid this problem by creating your own local, immutable copy of the current contents of this.sender, and reference that value in the closure:

val origSender = sender
f.onComplete {
    case Successs(x) => origSender ! x
    ...
}
like image 69
stew Avatar answered Sep 25 '22 11:09

stew


import akka.pattern.pipe

Does the trick. Doing:

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

replies back to the sender

like image 31
Jatin Avatar answered Sep 21 '22 11:09

Jatin