cap deploy:web:disable and Phusion Passenger (final update) 6

Posted by smoe Thu, 09 Oct 2008 20:17:00 GMT

This may still be useful to people in a shared hosting environment, but If you are administering your own server this hack is obsolete. As of Passenger 2.1.1 mod_rewrite is fully supported, or so I am told, I’ll try it out soon.
 
When you switch from mongrel to Passenger you will see many improvements. The web sites are faster, configuration is simpler, and deployment is easier. With the Passenger Apache module handling Ruby on Rails there are no separate application server processes, no proxy server calls, and you don’t need mod_rewrite for static content.
 
The only thing you lose are some Capistrano recipes: cap deploy:stop and cap deploy:web:disable will not work. I can live without deploy:stop. I don’t want my users to see "no response from server" or "upstream proxy server error" or any other error message that looks like something blew up. That’s why I like deploy:web:disable. I wish I never needed it but if something does go wrong, or a database needs to be reloaded or re indexed, deploy:web:disable is nice to have. The default maintenance.html page is a clean, simple message that shows you are in control. Problem is when you lose mod_rewrite you lose the mechanism that instructed Apache to skip the web app and show the maintenance page.
 
I’ve seen reports that you can set RailsAllowModRewrite on and only use mod_rewrite for the maintenance page, but it didn’t work for me. As far as I can tell Passenger and mod_rewrite just don’t work together. Passenger does a good job with static content so I don’t miss mod_rewrite, and it is still available to virtual hosts that are not Ruby on Rails applications.
 
What I came up with is a before_filter for the application controller. It’s not exactly the same thing. The application still needs to start up and serve the maintenance page, but if this is the first before filter there should be no database access and you can do almost anything you would do with a mod_rewrite disable.
 

To make it easy to copy around I put this mix-in module in lib/maintenance_mode.rb

module MaintenanceMode
protected
  def disabled?
    maintfile = RAILS_ROOT + "/public/system/maintenance.html"
    if FileTest::exist?(maintfile)
      send_file maintfile, :type => 'text/html; charset=utf-8', :disposition => 'inline'
    end
  end
end

And make these the first two lines in class ApplicationController, before any before_filters that might access the database.

  include MaintenanceMode
  before_filter :disabled?

And that’s all it takes to get cap deploy:web:disable to work again. This is the bit of code I put at the end of config/deploy.rb to replace start, stop and restart, and provide some handy Capistrano recipes for working with passenger.

namespace :deploy do
 desc "Restart Application"
 task :restart, :roles => :app do
   run "touch #{current_path}/tmp/restart.txt"
 end

 desc "Not used with Passenger"
 task :start, :roles => :app do
   # nothing
 end
 desc "Not used with Passenger"
 task :stop, :roles => :app do
   # nothing
 end
end

namespace :passenger do
 desc "passenger memory stats"
 task :memory, :roles => :app do
   run "passenger-memory-stats" do |channel, stream, data|
   puts data
 end

 desc "passenger general info"
 task :general, :roles => :app do
   run "sudo passenger-status"
 end
end

I think for my next Ruby on Rails post I’ll show a capistrano recipe for generating a custom maintenance.html page.