Adding code revision header to your apps

Posted by Dan Sosedoff on January 25, 2012

Sometimes its necessary to have a code revision tag somewhere on the website. Use cases are usually different and vary from just checking against the current revision, automatic upgrades and such.

If you’re rolling deployments with capistrano, it will insert the REVISION file under the app’s root dir with git sha or svn revision or whatever tag based on SCM of your choice.

Here is the simple rack middleware that injects that revision as a ‘X-REVISION’ header in responses.

module Rack
  class Revision
    @@revision = nil
    File = ::File
 
    def initialize(app, &block)
      @app   = app
      @block = block
      @file  = File.join(Dir.pwd, 'REVISION')
    end
 
    def call(env)
      status, headers, body = @app.call(env)
      headers['X-Revision'] = revision
      [status, headers, body]
    end
 
    protected
 
    def revision
      @@revision ||= read_revision
    end
 
    def read_revision
      File.exists?(@file) ? File.read(@file).strip : 'UNDEFINED'
    end
  end
end

For instance, just put that file as lib/rack/revision.rb and change your config.ru file:

require ::File.expand_path('../config/environment',  __FILE__)
use Rack::Revision
run YOUR_APP::Application

You’ll need to restart the app to apply the changes.

To test if it works just run:

curl -i -X HEAD "http://YOUR_WEBSITE/"

Sample output would be:

ETag: "8d6228d86642025c31e3d54e9a67b14b"
Cache-Control: max-age=0, private, must-revalidate
X-Runtime: 0.001491
X-Rack-Cache: miss
X-Revision: f8c51630843898e88848261dd5ebac3fdebc5e48

Using capistrano-unicorn with multistage environment

Posted by Dan Sosedoff on January 21, 2012

Awhile ago i create a capistrano-unicorn plugin for Capistrano that allows you to deploy your rails application using Unicorn. It works fine until you define multiple stages in your deployment configuration.

The issue – capistrano loads default configuration and then executes your staging task and overrides previously defined variables. Default environment before executing stage task is set to :production. So unless you define :rails_env, :unicorn_env, :app_env in your stage config it will use a wrong environment.

Lets take a look at sample deploy.rb file:

set :stages, %w(production staging)
set :default_stage, "staging"
require 'capistrano/ext/multistage'

You’ll need to add config/deploy/staging.rb and production.rb files:

set :domain,      "YOUR_HOST"
set :rails_env,   "staging"
set :unicorn_env, "staging"
set :app_env,     "staging"
 
role :web, domain
role :app, domain
role :db,  domain, :primary => true
 
set :deploy_to,   "/home/#{user}/#{application}/#{fetch :app_env}"
set :current_path, File.join(deploy_to, current_dir)

This should fix the problem with wrong rails env being passed to unicorn server.

Deploying Rails application with Capistrano and Unicorn

Posted by Dan Sosedoff on October 23, 2011

I’ve been switching all my new applications to Unicorn (nginx+unicorn) from Passenger (nginx+passenger). Passenger comes with an extension to nginx and needs to be compiled with nginx as a plugin. That requires additional maintenance on server and not a good idea in general when having more that just 1 ruby runtime on the server.

I use capistrano for all my apps and find it very useful for quick and handy deployments. After switch to unicorn i’ve been copying-and-pasting the same code over and over again, so i decided to move it to a separate gem.

Check out code on github – capistrano-unicorn.

Usage

Assuming that you already have your capistrano script ready, add gem to the Gemfile:

group :development do
  gem 'capistrano-unicorn'
end

Then, add requirement to the deploy.rb file (after all hooks):

require 'capistrano-unicorn'

Configuration

All unicorn configs should be placed under APP_ROOT/config/unicorn/ENVIRONMENT.rb
So, for each environment there should be a separate file.

Test if that worked:

cap unicorn:start
cap unicorn:stop
cap unicorn:reload

For more information check out github repository – capistrano-unicorn.

It is still under development, but basic functionality works fine.