Skip to content
stefri edited this page Aug 5, 2011 · 7 revisions

spray does not come with its own built-in web server. It merely provides a layer on top of an HTTP server that allows for easy and flexible definition of request handling logic.
When a client issues an HTTP request against a spray application the request is first handled by the underlying HTTP server (which, currently, has to be a servlet container). The HTTP server passes the request on to the server-specific ConnectorServlet (which is part of spray-server). The ConnectorServlet uses the asynchronous request handling API of the HTTP server to immediately suspend the request before passing it on to sprays RootService actor.

The RootService Actor

The RootService actor is a singleton actor that serves as the main gateway into your spray application. All incoming requests hit the RootService actor as RawRequestContext messages. The RootService actor creates a RequestContext instance for request and sends it off to all attached HttpService actors.

The HttpService Actors

The application logic behind your spray web service can be divided into several parts with each part "living" in its own HttpService actor. Many applications will not need more than one HttpService, but in some cases it might appear natural to have several.

All HttpService actors need to be registered with the RootService actor, from which point on they will receive incoming RequestContext instances. The job of an HttpService actor is to provide an execution context for its "route", which completes (resumes) the request at the earliest possible time.

Even though you can have many HttpService actors attached to the RootService every request should only be completed once. If two HttpService actors try to complete the same request one of them is going to "get through" first (and determine the response) while the other one is going to trigger an error.

The RequestContext

One key principle is that requests do not occupy a thread in the server JVM. Rather they are treated as simple messages that are passed along an actor chain / graph. Any actor getting a hold of the request can decide to complete it, store it away for later processing, ship it off to another actor and so on. The only requirement is that the request be completed before the timeout set at the time of request suspension expires. Otherwise the client will receive a 500 Internal Server Error response.

The actual objects being moved around as messages between actors are of type RequestContext. The central job of this immutable structure is to provide a container for two main things:

  • An instance of type HttpRequest, which immutably models every aspect of the client request that was received
  • A responder function of type RoutingResult => Unit, which is the entry point to a (potentially quite long) chain of functions that eventually trigger the sending of some response to the client

Clone this wiki locally