Spray Dead Letter msg

507 views Asked by At

I'm trying to execute the following code

trait CustomHttpService extends HttpService {

  import MyJsonProtocol._
  import spray.httpx.SprayJsonSupport._

  implicit def executionContext = actorRefFactory.dispatcher
  implicit val timeout = Timeout(5 seconds)

  val offerActor = actorRefFactory.actorOf(Props[OfferActor], "offer-actor")

  val defaultRoute = {
    path("offer" / JavaUUID) { uuid =>
      get {
        respondWithMediaType(`application/json`) {
          complete {
            (offerActor ? Get(uuid)).mapTo[Offer]
          }
        }
      }
    }
  }
}

class OfferActor extends Actor {
  override def receive = {
    case Get(id) =>
      val future = OfferService.genericService.getById(id)
      future.onComplete {
        case Success(s) =>
          s match {
            case Some(offer) => sender ! offer
            case None => println("none")
          }
        case Failure(f) => f
      }
    case id: String => println("received string id: " + id)
    case _ => println("receive nothing")
  }
}

Initially I was trying to return directly the future, but it was giving me an error, complaining about the promise that I was trying to cast to my Offer object.

Then I just ugly solve my future inside my actor to finally get the Offer and then return it to the sender.

Doing this I'm getting the following:

[06/09/2015 15:16:43.056] [spray-system-akka.actor.default-dispatcher-4] [akka://spray-system/deadLetters] Message [com.spray.entity.Offer] from Actor[akka://spray-system/user/spray-actor/offer-actor#-617290326] to Actor[akka://spray-system/deadLetters] was not delivered. [2] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.

Indeed, I'm sending a msg with an Offer that I got from the database.

Instead if I simply create an Offer like this, works perfectly.

case Get(id) => sender ! Offer(Some(id), "offer", new DateTime())

I'm believing the future.onComplete inside the actor is causing something wrong.

Any thoughts?

2

There are 2 answers

1
Gangstead On BEST ANSWER

sender is really a function, so you could write sender() to show that it is not just accessing an immutable value. When you call sender inside the future.onComplete the value of sender isn't valid anymore.

I've run into this problem before and the way I worked around was by saving the value of sender outside of the future:

class OfferActor extends Actor {
  override def receive = {
    case Get(id) =>
      val future = OfferService.genericService.getById(id)
      val replyTo = sender
      future.onComplete {
        case Success(s) =>
          s match {
            case Some(offer) => replyTo ! offer
            case None => println("none")
          }
        case Failure(f) => f
      }
    case id: String => println("received string id: " + id)
    case _ => println("receive nothing")
  }
}
0
Thiago Pereira On

Well, just solved it trying to block my future.

I just created a blocked version of

OfferService.genericService.getByIdBlocking(id)

Where I blocked it with

Await.result

then it worked!

So basically I had to let akka embrace my call with a future using the ask pattern but do blocking operations inside the actor.