Jan 8, 2009

Mongrel as a Library, not a Server

Most people who have done any Rails coding have at least heard of Mongrel, which is a widely-used web server for hosting Ruby web applications. Usually it is done with Rails, but I've been using it with Merb and it supposedly works with a number of frameworks.

One thing that is cool about Mongrel is that it is not really just a web server, rather a library for developing web servers. For example, the way Rails works with Mongrel is just a class called RailsHandler that inherits from Mongrel::HttpHandler, which then calls the appropriate controller from your class. The mongrel_rails script is just something that sets up the Rails environment and starts the server.

Suppose you wanted to write an application (notice it is not necessarily a web application, but could be) that could use HTTP to talk to other apps. You want something simple, you don't need Rails or any other framework to do anything for you. You can use Mongrel for this.

Here's some code:
# note that I grabbed some of this code from Mongrel's RDoc
require 'rubygems'
require 'mongrel'

class MyAwesomeHandler < Mongrel::HttpHandler
def process(request, response)
response.start(200) do |head, out|
head["Content-Type"] = "text/plain"
out.write("hi!\n")
end
end
end

server = Mongrel::HttpServer.new("0.0.0.0", 3000)

server.register("/", MyAwesomeHandler.new)

server_thread = server.run

# do your app logic here

server_thread.join
Make sure the mongrel gem is installed, and run this code. Go to your browser and type 'http://localhost:3000' and what you should see is a simple string that says "hi!".

So how does this work? It's pretty simple really. We create a class that handles an HTTP request. It has a process() method that gets two objects, the request info (contains any params passed) and the response info (the object that lets you respond). We then say we're doing plain text, and spit out a "hi!".
Outside the class we create an instance of the HTTP server with the HttpServer class (whoda thunk...), bind any requests to / to our awesome handler, and fire that server up. The run() method returns a thread object, which we can then treat as a regular old Ruby thread. At the end of the app, we join the thread to wait for it to finish (it never finishes, unless you press Ctrl+C).

So we haven't really created a web server here. Instead we've created an application that is capable of using HTTP to communicate (a web server is an example of an application that does this). Between the server.run and server_thread.join lines, you can do whatever you want, and the server thread just sits around waiting for any request to come in. In fact, you can store your own Ruby objects on your side and so long as you're coding in a thread-safe manner, you don't need memcached or a database to keep things! Pretty cool!

1 comment:

grant said...

I started playing with something similar a while back. I was going to "clone" web.py in Ruby.

Sadly, I lost interest pretty quickly... which is obvious if you look at the repo.