views:

65

answers:

1

A Phusion Passenger error message isn't what I want my visitors to see if they landed on my site while I'm updating the back end.

So how do I get around this? Is my deployment process flawed from the start? or is there something I'm missing out?

Here's my process of deployment, so you get the picture:

  • commit new updates to a git repo and push to remote
  • cap deploy
  • ssh [ip]
  • rake gems:install
  • rake db:migrate
  • cucumber

The time in between the cap deploy and the db:migrate or gems:install is when there is the error message or during longer maintenance.

An idea struck me around the head while I have been writing this: can I put these commands into my deployment recipe?

But what if maintenance is going to take an 30 mins or an hour, those commands won't solve the problem. how can I serve up a maintenance splash page to the visitor for this period of time?

thanks in advance.

+4  A: 

You should put up a maintenance page if the application is not going to be available for a while. I use this Capistrano task:

namespace :deploy do
  namespace :web do
    desc <<-DESC
      Present a maintenance page to visitors. Disables your application's web \
      interface by writing a "maintenance.html" file to each web server. The \
      servers must be configured to detect the presence of this file, and if \
      it is present, always display it instead of performing the request.

      By default, the maintenance page will just say the site is down for \
      "maintenance", and will be back "shortly", but you can customize the \
      page by specifying the REASON and UNTIL environment variables:

        $ cap deploy:web:disable \\
              REASON="a hardware upgrade" \\
              UNTIL="12pm Central Time"

      Further customization will require that you write your own task.
    DESC
    task :disable, :roles => :web do
      require 'erb'
      on_rollback { run "rm #{shared_path}/system/maintenance.html" }

      reason = ENV['REASON']
      deadline = ENV['UNTIL']      
      template = File.read('app/views/admin/maintenance.html.erb')
      page = ERB.new(template).result(binding)

      put page, "#{shared_path}/system/maintenance.html", :mode => 0644
    end
  end
end

The app/views/admin/maintenance.html.erb file should contain:

<p>We’re currently offline for <%= reason ? reason : 'maintenance' %> as of <%= Time.now.utc.strftime('%H:%M %Z') %>.</p>
<p>Sorry for the inconvenience. We’ll be back <%= deadline ? "by #{deadline}" : 'shortly' %>.</p>

The final step is to configure the Apache virtual host with some directives to look for the maintenance.html file and redirect all requests to it if it's present:

<IfModule mod_rewrite.c>
  RewriteEngine On

  # Redirect all requests to the maintenance page if present
  RewriteCond %{REQUEST_URI} !\.(css|gif|jpg|png)$
  RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
  RewriteCond %{SCRIPT_FILENAME} !maintenance.html
  RewriteRule ^.*$ /system/maintenance.html [L]
</IfModule>

To put the application into maintenance mode, run cap deploy:web:disable and to make it live again do cap deploy:web:enable.

John Topley
Wow, you really bowled me over with that answer! fantastic!
Joe
@Joe You're welcome!
John Topley