I have a Scala application using Akka that receives REST requests, makes some operations against a database, and responds with some information to the client. As it is, my db operations take a long time and my REST-enabled actor is unable to respond to new requests in the meantime, even though I could run lots of operations concurrently against the DB. I'm using the javax.ws.rs annotations to REST-enable methods in my actor.
The question; what is the best way to enable my application to handle a large number of concurrent requests?
EDIT: I'll add some sample code.
import se.scalablesolutions.akka.actor._
import javax.ws.rs._
@Path("/test")
class TestService {
@GET
def status() =
actorPool !! Status(session).
getOrElse(<error>Unable to connect to service</error>)
}
class TestActor {
def receive = {
case Status() => {
reply(SomeObject.slowDBMethod)
}
}
}
case class Status()
EDIT2: This is what I'm getting in the log. I'm sending the three requests from my browser as fast as I can switch tabs and press F5, but the RS bean still waits for the first request to complete before handling the next.
[INFO] [2010-08-29 16:27:03,232] [akka:event-driven:dispatcher:global-15] c.n.StatusActor: got Slow request
[INFO] [2010-08-29 16:27:06,916] [akka:event-driven:dispatcher:global-10] c.n.StatusActor: got Slow request
[INFO] [2010-08-29 16:27:10,589] [akka:event-driven:dispatcher:global-3] c.n.StatusActor: got Slow request
you seem to be using an older version of Akka.
I recommend to upgrade to 0.10 (which separates Actors and the RS-Beans), then you can use LoadBalancer1 (and2) to throttle the workload, or take advantage of the WorkStealingDispatcher3 (and4)
Does that help?
While I realize this thread is 4+ months stale now, it's worth noting that Akka has a new HTTP module implementation that transfers the request into an actor efficiently. This approach leverages the asynchronous servlet API (also works with Jetty continuations) to enable the suspended request to be passed through the system as a message and resumed at any point; eliminating, for instance, the need to use !! to trigger actor work and respond in the annotated POJO. Likewise, since the request is suspended in the container, and the context is flipped into an actor as quick as possible, there are no threads blocking to handle the response or future.
One naive way the above example might be rewritten today:
class TestEndpoint extends Actor with Endpoint {
def hook(uri:String) = uri == "/test"
def provide(uri:String) = actorOf[TestService].start
override def preStart = {
ActorRegister.actorsFor[classOf[RootEndpoint]).head ! Endpoint.Attach(hook, provide)
}
def receive = handleHttpRequest
}
class TestService extends Actor {
def receive = {
case get:Get =>
get.timeout(SomeObject.TimeoutInSeconds) // for example
get.OK(SomeObject.slowDBMethod)
case other:RequestMethod =>
other.NotAllowed("Invalid method for this endpoint")
}
}
More documentation can be found on the akka site: http://doc.akkasource.org/http
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With