Monday, July 27, 2009

mongrel_cluster, Rails 2.3.x, bad post, routing recognition

There is currently a problem running mongrel_cluster against a Rails 2.3.x application. The odd thing is that the problem only occurs when the first request to a newly started mongrel is a HTTP Post and not a HTTP GET. If the first request is a GET then it is handled fine, and all subsequent POST and GET are fine. But if the first hit to the Mongrel is a POST then bad things happen.

What kind of bad things? How about no form parameters or session parameters set by the time the request makes it to the controller bad. 

However, because the problem only happens if the first thing that hits a freshly started mongrel withing a mongrel_cluster is a POST, it can be a bit of a tough one to track down.

We first started seeing this as an occasional "routing recognition problem" that we had a devil of a time with. We all know about the _method hidden field added to Rails forms so that the controller can think that a HTTP PUT or HTTP DELETE was made, when really its POST with a hidden field. Unfortunately (or fortunately I suppose because it was the impetus to track this down), the URL recognition gets messed up when the action field is missing.

For example, if you are POSTing to /some_url/resource/1 with an _method of Delete, Rails wires that up to look like an HTTP DELETE, and wires it up accordingly in your controller. But, if the _method field is missing, then we have a POST to a resource, which is really expected to only ever be a GET....and bam the dreaded
"A ActionController::MethodNotAllowed occurred in application#index:
Only get, put, and delete requests are allowed."

When Rails is started via ./scrip/server and Mongrel is installed, Rails will use the new Mongrel handler which is designed for 2.3+ applications. However, when the Mongrels are started via mognrel_cluster the old cgi type of mongrel_handler is used, which I learned from finding this post:
http://www.timocracy.com/2009/04/15/problems-with-mongrel_cluster-and-rails-2-3-dispatcher-reloading-your-metal-every-request


Then, it looks like there is a problem with the "first" HTTP Request being a POST when going through the older cgi Mongrel handler. Which looks like it is already covered in this ticket:

http://rails.lighthouseapp.com/projects/8994/tickets/2844-bad-content-type-error-in-rack-10-with-first-cgi-mongrel-request#ticket-2844-7

We are currently investigating the benefits and options of moving our Rails 2.3 version of iZoca to either a Passenger based solution, or configuring some Rackup Mongrel instances. One of my concerns going forward will be that we don't make it more difficult down the road to introduce some Rack based middleware or even some Metal where appropriate. I don't think either of these solutions will make that task more or less difficult. We'll be doing some testing and benchmarking on both options.

3 comments:

  1. my team ran into this issue a few weeks ago, and I've been working on a few different angles for this. turns out for us we can't use passenger so here's my interim fix: http://gist.github.com/195369. not sure where we'll go from here though.

    ReplyDelete
  2. Ryan, have you checked to see if this is still a problem in Rails 2.3.4? I haven't verified it yet, but was told through the rumor mill that it was supposed to have been addressed in 2.3.4

    I was hoping that it was, and plan to investigate it shortly so that I can move back to a mongrel_cluster setup myself.

    ReplyDelete
  3. Yes, this is still broken in 2.3.4. I was bitten by this bug after updating from 2.0.2 to 2.3.4. My "fix" essentially "reverts" the commit that introduced this "bug". (http://github.com/rails/rails/commit/61a14569379974564a98b229ab595dfec18d2059) I'm not sure this will get fixed since CGI is being deprecated and mongrel appears to be no longer maintained. :/ Bummer.

    ReplyDelete