Right out of the box Agoo is fast but to take full advantage of all Agoo's features some configuration changes can be made. Those changes allow Agoo to circumvent the default Rails and Rack behavior.
Both Rack and Rails with Rack expect to handle all HTTP requests. The call
method is expected to handle serving static assets as well as Ruby
processing. Usually a stack of middleware is used for processing.
The Rack approach is fine except that using a middleware stack to handle
requests for static assets is expensive. Fortunately Rack expects static
assests to be in the ./public
directory by convention. Rails deviates a bit
and sets up an alias for a set of directories so that a request to /assets
gets resolved to a lookup in one of several directories. The first match is
then returned. Its a nice feature. The /assets
directory group is described
in the Rails.configuration.assets.paths
variable.
Rack does the de-multiplexing of HTTP requests in Ruby. That means a request
on /hello
and one on /goodbye
hit a Ruby call to decide that Ruby handler
should take care of the request. Many other web servers handle that type of
de-multiplexing before passing control to the handlers.
Agoo has some options to work around the Rack and Rails defaults while preserving the overall behavior.
The Ruby middleware stack isn't really needed to serve static assets. By
default when rackup
is used with Rails requests on /assets
is resolved
into a check of the value of Rails.configuration.assets.paths
at start up
just as Rails does. The difference is that request is handled completely by
Agoo and never touches Ruby code. This results in several orders of magnitude
better performance.
For straight Rack, when rackup
is called or when ever the
Rack::Handler::Agoo
handler is used the ./public
directory is checked
before calling the Ruby handle call
method. This is controlled by the rmux
option which default to true. Calling rackup
with an argument of -O root_first=false
turns that option off.
To set up path groups like the /assets
group that Rails uses a call to
Agoo::Server.path_group
is made.
In any non-trivial application multiple Ruby classes are used to process
requests. Maybe /users
is handle by one class and /articles
is handled by
another. In Rails those classes are buried deep within Rails. You can still
bypass Rails and Rack middleware if you want to for ancillary handlers. If
building an application directly using the Rack spec and want take a more
direct approach to invoking handlers then the Agoo de-multiplexing options
make the application request handling much simpler.
Setting up handlers for specific paths uses the Agoo::Server.handle
method. When a request arrives each handler path is checked in the order they
were registered. As and example, if these two calls were made.
Agoo::Server.handle(nil, '/one', FirstHandler)
Agoo::Server.handle(nil, '/**', CatchAll)
If a request arrive on /one
the FirstHandler
will be called. If on /two
the CatchAll
handler will be called.
The handlers paths can be set up using rackup
as well. Since rackup
already registers /**
to the Rack handler it is the CatchAll
in the above
example. To register handlers before that the -O /one=FirstHandle
option is
added to the rackup
arguments.
Using both static asset configurations and de-multiplexing will give the best performance. Couple that with Agoo's cluster option on a multithreaded machine give an even bigger win.
For a rackup
setup with static assets in ./assets
and a handler for
/help
that uses the HelpMe
class.
rackup -d ./assets -O /help=HelpMe
For a Ruby startup using ruby app.rb
add these to the app to use ./public
for static assets but add a group that handles assets at ./assets
and also
./public/assets
.
Agoo::Server.init(9292, `./public`, root_first: true)
Agoo::Server.path_group('./assets`, [`./assets`, `./public/assets'])