Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sender becomes Actor[akka://Main/deadLetters]

I can't figure out why do I have the error "deadLetters"

class MyActor extends Actor {

  private def getIdList = Future { blocking(getIdListSync) }

  private def getIdListSync = {
    val inputStreamRaw = new URL(url).openConnection.getInputStream
    val inputStream = scala.io.Source fromInputStream inputStreamRaw
    val json = parse(inputStream getLines() mkString "\n")
    val jsonIds = json \ "ids" \\ classOf[JInt]
    jsonIds take idLimit map (_.toInt)
  }

  def receive = {
    case Get =>

        //doesn't work, the error is "sender" becomes "Actor[akka://Main/deadLetters]"

//      getIdList onComplete {
//        case Success(idList) =>
//          sender ! Result(idList)
//
//        case Failure(e) => // todo
//      }

      //works well
      val idList = getInternalIdListSync
      sender ! Result(idList)

  }
}

As you can see, sender becomes Actor[akka://Main/deadLetters] in case of using Future and blocking in the method titled getIdList. Why is that? Shouldn't I use that?

like image 656
Incerteza Avatar asked Dec 18 '13 05:12

Incerteza


2 Answers

The problem is that you call sender in an async function block. There is a simple rule for that:

never close over the sender method in a code block that may get executed asynchronously

sender is a function that returns the sender of the currently processed message. The problem is that, if you call sender in a callback like onComplete this callback gets executed asynchronously. That means that in the meantime the actor may process other messages and therefore the sender function may not report the sender of the original message.

One way to avoid that is to store the sender in a local variable before execution asynchronous code:

def receive = {
  case Get =>
    val s = sender

    // call an asynchronous function
    myAsyncFunction onComplete{ result =>
      s ! result
    }
}

Another way is to use the akka pipeTo function as @Vadzim pointed out:

import akka.pattern.pipe

def receive = {
  case Get =>
    // call an asynchronous function
    val result = myAsyncFunction

    result pipeTo sender
}

More information about that can be find in the akka documentation: http://doc.akka.io/docs/akka/snapshot/scala/futures.html#Use_With_Actors

like image 153
tmbo Avatar answered Oct 02 '22 03:10

tmbo


Just use

import akka.pattern.pipe
getIdList pipeTo sender

See for explanation: Akka: Send a future message to an Actor

like image 30
Vadzim Avatar answered Oct 02 '22 05:10

Vadzim