- Clarified the distinction between Rails Metal and Rack middleware after more information from @Josh in the comments. Thanks!
- Read more about metal from DHH on the Official Rails Blog.
- Demonstrate Testing Metal end points
- Update Poller example to match new style
- Cover Sinatra Integration
- Correct benchmarks
Josh Peek committed a new feature to Edge Rails today: Rails Metal. After the recent work to replace Rails’ crufty request processing code with Rack and integrate its middleware support, Rails Metal is a logical progression that allows Rails apps to use the power of Rack middleware to create super-fast actions.
For example, here’s a sample “Hello World” Metal:
And for comparison, a “Hello World” controller:
So, let’s fire up
ruby script/server and see what this gives us:
So, the point of all of these other “micro-frameworks” is that they’re faster than Rails, right? Let’s benchmark this new “Hello World” Metal:
For this trivial “Hello World” benchmark, Rails Metal is 2.8x faster than a Controller. Awesome. Have a couple actions of your app you need to optimize? Instead of breaking them out into a separate application using a micro-framework, add a Metal inside your existing app. You get the performance benefits of processing requests outside of ActionPack, and it’s all integrated as a part of your Rails app. Easy!
You can now also use Sinatra to create Metal end points:
First person to show the use of a Merb app as a Metal end point wins a prize.
Additionaly, Rails Metal are able to be executed in a separate process
from your Rails application using
This runs the Poller Metal separeately from Rails, on it’s own port
rackup defaults to
9292). This is perfect if you have an action
that’s taking a very long time (for example a file upload) that you’d
like to split out from the normal Rails request processing queue.
Update: After several people commented asking how to test metal, DHH chimed in and recommend Integration Testing for Metal end points, as they hit the whole stack, and I submitted a patch cleaning up the Integration Testing behavior of Metal. Testing Metal end points now works just like any other Integration test:
Fun With Middleware
So, essentially, Rails Metal is a thin wrapper around Rails’ new Rack middleware support. Rack middleware is pretty powerful stuff: framework-independent components that process requests independently or in concert with other middleware. For example, here’s a simple piece of Rack middleware that runs a regex on responses:
To use this rack middleware in Rails, add this line to your
Restart your server, and check out what happens:
The Rack middleware filtered the output of the Metal we created before. This works with output generated by normal controllers and everything too. The possible uses of this pattern are endless:
- Single Sign On
- Request/Response Signing (think OAuth)
- Asset Compression
rack-contrib is a nice collection of Rack middleware if you’re interested in more examples.
Rails Metal is a simple wrapper around the existing (yet undocumented) Rack middleware support in Edge Rails that attempts to DRY the process of using middleware to create endpoints (like a poller) as opposed to filters (which are better implemented as traditional middleware, like the examples above). For example, Rails Metal might be used:
- To speed up a ‘poller’ action called by all active users of a popular web-based chat application every 3 seconds (hint: Campfire).
- To improve the performance of any API endpoint
- To process file uploads outside of the Rails request queue
- To authorize delivery of cached content
We don’t need no stinking micro-frameworks
With the additional of Metal and Rack middleware support, Rails effectively includes a micro-framework of its own; one that either tighly integrates with Rails or is executed separately - whichever the need dictates.
This is a great response by the Rails team to all of the buzz surrouding micro-frameworks: a micro-framework with the power of Rails. I’m definitely going to try this approach to squeeze a couple extra requests per second out of a heavily trafficked API call - let me know in the comments if you find a use for it.