☀️ nick quaranto

Load Rails conditionally with Rack

One of the great things about Gemcutter is that it’s using Sinatra via Rails Metal to serve up the gems. Recently, I had to run some long migrations (~10 minutes) and I’m sure we’ll have some more in the future. Since the gem server is decoupled from the Rails app, some clever Rack loading now allows us to continue to serve gems even when we’re down for maintenance.

The config.ru now looks like this:

if ENV['MAINTENANCE_MODE']
  require File.join('vendor', 'bundler_gems', 'environment')
  require File.join('config', 'environment')
 
  use Rack::Static,
    :urls => ["/index.html",
              "/favicon.ico",
              "/images",
              "/stylesheets"],
    :root => "public/maintenance"
  use Hostess
  use Rack::Maintenance,
    :file => File.join('public', 'maintenance', 'index.html')
  run Sinatra::Application
else
  require 'thin'
 
  run Rack::Adapter::Rails.new(:environment => ENV['RAILS_ENV'])
end

So now, Heroku treats Gemcutter as a Rack app, and not a pure Rails app. Normally, it’ll just use Thin and boot up Rails as normal with Rack::Adapter::Rails. script/server still works as normal, too, but I’ll probably use shotgun instead.

The fun begins when you run MAINTENANCE_MODE=on rackup. The following happens from there:

And boom, we have a read-only site that continues to serve gems. Rack rules.