6
votes

I implement a REST service using Spray.io framework. Such service must receive some "search" queries, process them and send result back to the client(s). The code that perfrom searching located in separate actor - SearchActor, so after receiving (JSON) query from user, i re-send (using ask pattern) this query to my SearchActor. But what i don't really understand it's how i must implement interaction between spray.io route actor and my SearchActor.

I see here several variants but which one is more correct and why?

  1. Create one instance of SearchActor at startup and send every request to this actor
  2. For every request create new instance of SearchActor
  3. Create pool of SearchActor actors at startup and send requests to this pool
2

2 Answers

2
votes

You're not forced to use the ask pattern. In fact, it will create a thread for each of your request and this is probably not what you want. I would recommend that you use a tell instead. You do this by spawning a new Actor for each request (less expensive than a thread), that has the RequestContext in one of its constructor fields. You will use this context to give the response back, typically with its complete method.

Example code.

class RESTActor extends HttpService {
  val route = path("mypath") ~ post {
    entity(as[SearchActor.Search]) { search => ctx =>
      SearchActor(ctx) ! search
    }
  }
}

case class SearchActor(ctx: RequestContext) {
  def receive = {
    case msg: Search => //... search process
    case msg: Result => ctx.complete(msg) // sends back reply
  }
}
1
votes

Variant #1 is out of question after the initial implementation - you would want to scale out, so single blocking actor is bad.

Variants #2 and #3 are not very different - creation of new actor is cheap and has minimal overhead. As your actors may die often (i.e. backend is not available), i would say that #2 is the way to go.

Concrete implementation idea is shown at http://techblog.net-a-porter.com/2013/12/ask-tell-and-per-request-actors/