Introducing Rails Metal
Posted by David December 17, 2008 @ 11:08 AM
Rails Edge adopted Rack a while back and we’ve been exploring ways to expose that better. The first thing we did was to make it really easy to hook up any piece of Rack middleware in front of a Rails request. In your config/environment.rb file, you can do:
config.middlewares.use(Rack::Cache, :verbose => true)
This will make your application use Ryan Tomayko’s excellent Rack::Cache middleware for better HTTP caching. There are lots of other great generic, reusable Rack middleware pieces. Do go shopping.
But there’s another use case where Rack also comes in handy. If you have a Rails application that has service end points that need to be really, really fast. So fast that the few milliseconds that a trip through the Rails router and Action Controller path is too much.
For this scenario, we’ve built a thin wrapper around the generic Rack middleware and given it a place in the hierarchy along with the name “Metal”. Rails Metal is meant for things like the Campfire poller service, which is doing hundreds of requests per second and needs to be really fast and is at the same time really simple (2 database calls and returning a string). This service is currently written in C, but we’ll look into converting it to Rails Metal instead.
Rails Metal is a subset of Rack middleware
Think of Rails Metal as a subset of middleware intended for application-specific end points that need the extra speed (“write to the metal”, hence the name). Thanks to recent adoption of Rack sessions, these pieces of metal even have access to the same session as Rails. You can either run them as part of the Rails process or run them as individual services through rackup.
We’ve even included a generator for Metal, which by default will create a stub ala:
class Poller
def self.call(env)
if env["PATH_INFO"] =~ /^\/poller/
[200, {"Content-Type" => "text/html"}, "Hello, World!"]
else
[404, {"Content-Type" => "text/html"}, "Not Found"]
end
end
end
As you can see, all this does is capture requests to /poller and return “Hello, World!” (and the request is not for /poller, it’ll let the Rails router handle it—that’s what the 404 return does). It will do that just about as fast as is technically possible in Rack (cue useless metric of how Rails now has the fastest, most meaningless “hello world” stat!!).
Note that this is a pretty specialized tool. While you could write an entire Rails application using just metal, it would be a terrible idea in most cases. The vast majority of applications out there will never do what they do so fast that the overhead of the already heavily optimized Rails router and Action Controller execution path will matter one bit (pick up Michael Koziarski’s talk on Rails Performance through torrent for more on this).
Also, if you’re writing a generic filter in the vein of Rack::Cache, Metal is not the right choice either. You should just be creating regular middleware which can be shared across all Rack applications.
But for those few, specialized cases where you just need as much raw speed as possible, Metal can be exactly what the doctor ordered. It allows you to have the best of both worlds in one package. The lowest possible overhead for a Rack application when that matters and the full-featured goodness of Action Controller when it doesn’t.
We hope you like this. Josh Peek has putting tireless hours into getting Rails on Rack and this is just the latest product of his efforts. Thanks a bunch, Josh!
Update: Jesse Newland wrote up a great introduction to Metal as well. It includes benchmarks and even more examples!
Update 2: Changed code example to match latest style.

nice work, josh. keep up the good work.
You guys are ruining the “Rails doesn’t scale” meme, dammit
This is really fantastic … there have been a few cases where I’ve needed poller scripts exactly like these to try and eke out every last bit of performance.
Very excited to give this a try in the Exceptional API.
This is perfect, saves me some ugly workarounds.
does this make rack-rolling everyone far easier?
http://github.com/jchupp/rack-roll/
sadly, i did not make this middleware, but i’m damn sure i’m gonna use it someday ;)
This rocks, I can see how it can prove useful for hammering requests.
The video ParisOnRails you linked has very crappy audio… :(
I might be missing something, but doesn’t Rack do all this already?
Dick, in the same sense that Ruby does everything Rails does. You just have to write it. Metal is making an aspect of Rack more accessible, easier to use, and a better fit inside of Rails. Just like everything else in Rails.
this is fantastic josh. thanks for all of your hard work on this.
DHH: Out of curiosity, is there a reason mongrel handlers were not originally satisfactory, but Rails Metal will be? I got the impression initially that Campfire dropped down to C due to a speed limitation with Ruby, not Rails.
In any event, good work on Rails Metal. Using Rack really exposes some exciting possibilities for getting closer to the metal both for returning a specific response and mutating the request/response as it goes through Rack.
It’s great to see these innovations make their way back into Rails. Very exciting times!
You mention in the article “that’s what the call to super does ”, but you don’t actually have that in the code example.
Justin, the call to super was removed in a later commit to make Metal and end point, rather than middleware. See http://github.com/rails/rails/commit/61a41154f7d50099da371e0d2f22fd25ab9113c2
This is really exciting. I’m working on a project where this might come in very handy!
Thanks for the great work.
That’s fantastic.
Thanks Josh for the great work
@Yehuda : I don’t know for sure, but my guess is that mongrel handlers are very tied to a single deployment strategy – mongrel, while rack convention abstracts the underlying webserver.
Rails is nice, but Merb is the future.
Mad props to Josh!
Didn’t Ezra Zygmuntowicz also have a big hand in bringing Rack over to Rails from Merb though?
He wrote about his initial work back in April: http://brainspl.at/articles/2008/04/25/hey-rails-nice-rack
@glenn irrelevant – metal takes advantage of a great piece of tech in the ruby ecosystem.
DHH, great work on making it more available to rails ‘grammers! And thanks are due to everyone else who made this possible, chris2, ezmobius, etc.
You mention that with sessions now being accessible within Rack, we can get access to them within Metal, but after an hour of Googling and code digging, I haven’t been able to find any substantive information showing what syntax could make that happen.
Any clues? I’m using an ActiveRecord session store, if it matters.
Its really fantastic. Will surely saves lots of extra work.
Dear Sir or Madam: We are one of the biggest mechanical spare parts manufactures in China. Mainly serve foreign market and can produce according to your drawings. Our factory mainly produces varied casting, forging, stamping etc. We have a set of complete control system and advanced quality testing equipment. So we are able to supply with high quality products. Our price is reasonable, delivery prompt. If you want to reduce your cost and enhance the profit please contact us as soon as possible. If you want to know more about our company please visit our website:http://www.m-electrical.com
John Fu sales manager
JiNing RuiDe Mechanical Electrical Co.,Ltd Address:No.36 HongXing central road, JiNing City, ShanDong Prov. China 272100 Tel:0086-537-3288166 Fax:0086-537-3288187 E-mail:rdjd@m-electrical.com; John-Fu888@Hotmail.com http://www.m-electrical.com