Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling an Actor in a Spray route and waiting for the Actor's response

After have used Play! Framework for a while, I'm taking a first look to Spray. I started from a sample I found on GitHub, now I want to modify it but it's not easy for me to get how it works.

How can I wait for a message from an Actor in the code below?

package api

import akka.actor.ActorRef
import scala.concurrent.ExecutionContext
import spray.routing.Directives
import core.ClassifierActor

class ClassifierService(classifier: ActorRef)(implicit executionContext: ExecutionContext)
  extends Directives with DefaultJsonFormats {

  import ClassifierActor._

  implicit val classifyMessageFormat = jsonFormat4(ClassifyMessage)

  val route =
    path("classify") {
      post {
        handleWith { 
          // The ClassifierActor gets a ClassifyMessage and 
          // sends a ClassifiedMessage back to the sender.
          // How can wait for the ClassifiedMessage here 
          // and send a HttpResponse back?
          cm: ClassifyMessage => classifier ! cm
          // ???
        }
      }
    }

}
like image 888
Max Avatar asked Oct 11 '14 11:10

Max


2 Answers

Spray is already based on akka.io

Thus, if you want just to complete your route with actor response, you could use ask pattern

import akka.pattern.ask  
import scala.concurrent.duration._
implicit val timeout = Timeout(5 seconds) // needed for `?` below

 val route =
    path("classify") {
      post {
        onComplete(actorResponse(yourActor, yourMessage)) {
          complete(_)
        }
      }
    }

def actorResponse[T](actor: ActorRef, msg: ClassifyMessage): Future[T] = 
(actor ? msg).mapTo[T]

If you want to forward request to your actor model and complete route somewhere in actor system, you need to forward RequestContext to actors. Maybe, this example could help you. Good luck!

like image 160
hellraiser Avatar answered Oct 18 '22 05:10

hellraiser


Take a look at my example project. This service uses Futures to complete routes. Like Rup commented, it's bad practice to wait for a response. Return a future immediately and let it complete when it gets a result.

In your example classifier ! cm is using the actor "tell" pattern. It sends a message cm to the classifier actor and moves on. If you want it to expect a response back in a future use the "ask" pattern: classifier ? cm. In your cm actor's receive method you will return a future with sender ! responseMsg which will return in a future.

like image 44
Gangstead Avatar answered Oct 18 '22 03:10

Gangstead