Time for a preview
Esther Dyson has kind words about the thing I'm working on with a super cool team at Adaptive Path.
If you've got a blog, sign up for an invitation.
Esther Dyson has kind words about the thing I'm working on with a super cool team at Adaptive Path.
If you've got a blog, sign up for an invitation.
For reasons I won't get into, it became necessary to make Rails go faster. But only for a couple url's, and without need for the majority of the framework. For a while, we ran these scripts with raw FCGI and a simplified Dispatcher that let you work with the request and response directly, bypassing the main Rails workflow.
But now we have the wonderful RailsFCGIHandler, with graceful signal handling, app reloading and more. I wanted our custom dispatcher to benefit from that too.
So, we want to use the RailsFCGIHandler but handle requests with our stripped down Dispatcher before Rails gets to it. My first thought was to override FCGIHandler#process_request
class CustomRailsFCGIHandler def process_request(cgi) MyDispatcher.dispatch(cgi) # Dispatcher.dispatch(cgi) rescue Object => e raise if SignalException === e dispatcher_error(e) end end CustomRailsFCGIHandler.process!
That's ok, but we've duplicated some tricky exception handling logic. Even worse, it's treating Ruby like a static language. We can do much better. First, there's no need to subclass RailsFCGIHandler. Simply opening the class and redefining process_request would do the same thing.
But, here's the cool part. We don't have to modify RailsFCGIHandler at all! The only functionality we need to change is in Dispatcher, so let's just modify it.
class Dispatcher class <<self alias :old_dispatch :dispatch end def self.dispatch(cgi) SimpleDispatcher.dispatch(cgi,false) do |request, response| case request.path when "/one" then Tracker::Controller.process(request, response, :one) when "/two" then Tracker::Controller.process(request, response, :two) else old_dispatch(cgi) end end end end RailsFCGIHandler.process!
That's it. Now our two high-availability url's are handled while still supporting Rails' normal workflow.
Here's SimpleDispatcher for reference. All it does is instantiate Rails' request and response objects, yield them, then take care of session propagation and write a response.
class SimpleDispatcher def self.dispatch(cgi = CGI.new, session_options = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS) request, response = ActionController::CgiRequest.new(cgi, session_options), ActionController::CgiResponse.new(cgi) begin yield request, response rescue response.body << $!.to_s ensure request.session.update if request.session && !request.session.kind_of?(Hash) response.out unless response.body.empty? end end end
Back to Dependency Injection. In a static language, hardcoding Dispatcher.dispatch(cgi) would have been a sin. It forever ties us to a specific implementation. Design patterns help - template method or factory method come to mind. Or using a DI container with setter injection. But each of these techniques causes excess overhead in both usage and design.
The Ruby way gives us a simple (almost naïve) implementation that's as flexible as the most complicated architectural patterns.
This point is worth repeating. Without any coding or design overhead, the result is highly flexible. Sure you can accomplish the same result in Java, et al but how many more lines of code+config+tests did it take?
When I worked in Java, dependency injection was a really cool, life saving technique. When I first came to Ruby, I immediately wondered about libraries for DI, Mock Objects and other such things.
It quickly became obvious that none of these things are all that necessary. Jim Weirich sums it all up perfectly in Dependency Injection: Vitally Important or Totally Irrelevant?
I grabbed it from svn and started playing around last night. Today there's a manual on it. Nothing much to say except SwitchTower looks super, super sweet.
Combine that with migrations and FCGI scripts and wow, things just got simpler. Simpler is good.
I look forward to testing SwitchTower out on a few small projects in the next couple days, and then using it for the big one.
(announcement on "the big one" coming soonish)
FOSCON was great. Thank you pdx.rb for putting on the event!
Keep an eye out for Rails/Flash integration using a Cocoa-like windowing system. Amazing, made-me-drool stuff. And all he showed was sample code.
Glenn Vanderburg's talk on domain specific languages for programmers was enough to make me rewrite a large chunk of code as soon as I got home. Update slides here
_why's performance was something to be seen. Truly.
Shellac
In the second installment of bands I thought I'd never get to see we have Shellac. Stood so close I kept cool from the wind coming out of Todd Trainer's kick drum.
Check out all photos, or just my favorite