[Mongrel] mongrel and long lived connections

Zed A. Shaw zedshaw at zedshaw.com
Tue Dec 5 20:34:41 EST 2006


On Tue, 5 Dec 2006 13:08:14 -0800
"Joseph McDonald" <superjoe at gmail.com> wrote:

> I understand that rails is not thread safe, but this is not using
> rails or any part of rails. It just sets up a simple handler.  but
> registering that handler seems to allow only one instance of that
> handler to run at a time.

I think part of your confusion (and others) is the association of HttpHandlers with HttpRequests and HttpResponses.  Also, how they're run in the life cycle of a Mongrel HTTP request process.

First, Mongrel accepts remote clients and creates one Thread for each request.  Mongrel also enforces a single request/response using Connect:close headers because Ruby only supports 1024 files (so far).  If Mongrel doesn't do this then people like yourself can write a simple "trickle attack" client that hits the Mongrel server, opens a bunch of continuous connections, and then eat up all available files very quickly.  Basically, a DDoS attack that's very simple to do.

So, keep that in mind with your comet thing.  You'll have to also keep track of the number of active connections and start getting into old school capacity planning to figure out how many mongrel processes are needed to service your appropriate user load.

Second thing is that you can register multiple HttpHandler objects with a URIClassifier at a URL path, but that each one is run in sequence and they are run across all the threads.  This means that *you* have to keep the threading straight in your HttpHandler since that same object's state could be used by 500+ threads at once.  This is also why each handler's process(req,resp) method is given all the stuff it needs in the parameters.

For example, this is *really* bad:

class DumbAssHandler < HttpHandler
  def initialize()
    @afile = open("somefile.txt")
  end
  def process(req, response)
    @afile.write(req.params["X-Someheader"])
  end
end

The problem is a *single* instance of DumbAssHandler is shared amongst *ALL* the threads that call DumbAssHandler::process().  When you start writing to @afile it'll get all nasty and confused on you, but what's worse is Ruby's threading isn't so clear on this so it *might* work most of the time, and then one day you hit that magic thread or switch to Linux and all hell breaks loose.

Finally, each client processing Thread gets its very own HttpRequest and HttpResponse object, so within the process() method you can go to town on it without worrying about locking problems.  If you need to store stuff someplace so that it's not shared then just toss it into the req.params[] as a symbol with a funky name.  You can also use Thread.current[] to store things, but there's a hidden danger:  The GC doesn't run on Threads very often and not the same as other stuff, so things in Thread.current[] tend to live for longer than you expect.

Anyway, hope that helps you out.

-- 
Zed A. Shaw, MUDCRAP-CE Master Black Belt Sifu
http://www.zedshaw.com/
http://www.awprofessional.com/title/0321483502 -- The Mongrel Book
http://mongrel.rubyforge.org/
http://www.lingr.com/room/3yXhqKbfPy8 -- Come get help.


More information about the Mongrel-users mailing list