fatlog
fatlog

Reputation: 1192

Akka Ask & Futures

I'm an akka noob so apologies!

I'm playing around with a system that uses Spray and Akka. I'm using the following code snippet to send a message to another actor. It uses ask which, from what I understand will return a future which is resolved in "mapTo" and "map". I then return the result to the users using Sprays "complete" directive.

val response = (worker ? Create(json))
            .mapTo[Ok]
            .map(result => s"I got a response: ${result}")
            .recover { case _ => "error" }

complete(response)

My question is, since this is a future, do I need to be worried about sending the correct response to the client? In some code samples I see examples where the actorRef to reply to is sent as part of the request...

// set reply to actor
val replyTo = sender() // important to not close over sender()

// create actor that collects replies from workers
val aggregator = context.actorOf(Props(
    classOf[StatsAggregator], words.size, replyTo))

Then in the receiving actor...

replyTo ! SendResult

Should I be passing the "replyTo" actor as part of the request or is this all taken care of in the mapTo?

Thanks in advance!

Upvotes: 0

Views: 423

Answers (1)

Ivan Stanislavciuc
Ivan Stanislavciuc

Reputation: 7275

The complete directive will send back a response to http/https client of your service. You don't need to do more than that. Please note that your code swallows errors by making recover on a future. Spray will treat it as a success and will return status code 200.

The last and most importantly, your worker has to reply with Ok message back like this.

class Worker extends Actor {
    def receive: Receive = {
        case Create(json) => 
        //do some staff with json
        sender() ! Ok // This Ok message will be passed in the future in spray route
    }
}

The replyTo idiom is needed only when worker uses Future internally to process the work load. As it in the following example

class Worker extends Actor {
    def recieve: Recieve = {
        case Create(json) => 
            val future = Future{
                //do some staff with json
            }

            val replyTo = sender()

            future.onComplete {
                case scala.util.Success(result) => 
                    replyTo ! Ok
                case scala.util.Failure(ex) => 
                    replyTo ! akka.actor.Status.Failure(ex)    
            }
    }
}

The replyTo is needed to fix actual sender of the message since onComplete may be executed within a different actor context that can point to a different sender resulting in message being sent to a wrong actor.

Upvotes: 1

Related Questions