1
votes

I am using Scala with Akka actors. I know that an actor has a mailbox. So any communication with the actor is serialized. I have an actor that does a certain job--say it downloads an image.

class DownloadImageActor(implicit val injector: Injector) extends Actor with Injectable {
  val imageDownloadService = inject[ImageDownloadService]
  implicit val ec = inject[ExecutionContext]

  override def receive: Receive = {
    case DownloadImage(jobId, imageUrl) =>
      imageDownloadService.downloadImage(imageUrl).onComplete {
        case Success(image) =>
          sender() ! ImageDownloadSuccess(imageUrl, image, jobId)
        case Failure(e) =>
          sender() ! ImageDownloadFail(imageUrl, e, jobId)
      }
  }
}

As you can see, the actor downloads the image in an async fashion. imageDownloadService.downloadImage returns a Future on whose completion a message is sent to the sender. Now this is where I get the dead letters encountered message.

Where have I gone wrong?



EDIT #1

The parent actor which sends message to the download actor

class ParentActor(implicit val injector : Injector) extends Actor with Injectable {

  val downloadImageActor = inject[ActorRef](identified by "ImageDownloadActor")


  override def receive: Receive = {
    case DownloadImages(urls, _id) => urls.foreach(url =>
      downloadImageActor ! DownloadImage(id, imageUrl = url)
    )
    case ImageDownloadSuccess(image : Image) =>
  }
}
1
did you check whether the sender session is already terminated? and can we see the implementation of your Actor reference ? because Dead Letter cause when then Actor reference for Parent Actor is already terminated.HuntsMan
@HuntsMan : I have added the code of the parent actor.Ashwin
@HuntsMan : Is the parent actor terminating itself automatically?Ashwin
@lagom : Hey your answer actually worked! Having the reference of the parent actor outside the complete blocked worked! Can you please add that as the answerAshwin
@Ashwin Yeah, I undelete the answer now if it won't give confuse to other readers. But I still don't know what Having the reference of the parent actor outside the complete blocked mean, could you help edit my answer to give a workable solution so benefit to others? Thanks.atline

1 Answers

-1
votes

Don't know if any other problem, but the method you use sender in Future is wrong, you need to assign it to a new variable, then combine the onComplete callback it forms a closure which will not be override by other actor handle.

In your code, need to add lineA, and replace lineB, lineC with lineD, lineE. Or you may want to have a look for pipeTo function of Future.

class DownloadImageActor(implicit val injector : Injector)  extends Actor with Injectable{
  val imageDownloadService = inject[ImageDownloadService]
  implicit val ec = inject[ExecutionContext]

  override def receive: Receive = {
    case DownloadImage(jobId, imageUrl) => 
      val client = sender // lineA
      imageDownloadService.downloadImage(imageUrl).onComplete {
      //case Success(image) => sender() !  ImageDownloadSuccess(imageUrl, image, jobId) // lineB
      //case Failure(e) => sender() !  ImageDownloadFail(imageUrl,e, jobId) // lineC
      case Success(image) => client !  ImageDownloadSuccess(imageUrl, image, jobId) // lineD
      case Failure(e) => client !  ImageDownloadFail(imageUrl,e, jobId) // lineE
    }
  }
}