Pascal’s svn and Capistrano Cheat Sheet

Here’s my recipe to get a source tree commited into subversion, then setup Capistrano and then deploy the application on a production server.
I’ve done this many times, and everytime I stumble of one or more steps to find find what comes next, what path to use, etc. So here’s a note to hopefully settle this once and for all.

Assumes that the subversion database is created on domain.net under /home/psq/svn/domainsvn. Assumes that the initial “domain” directory contains trunk, tags and branches and that you are deploying the trunk.

cd domain
svn import . svn+ssh://domain.net/home/psq/svn/domainsvn

mkdir domainsvn
cd domainsvn
svn co svn+ssh://domain.net/home/psq/svn/domainsvn/trunk .

cap -A .

svn add config/deploy.rb
svn add lib/tasks/capistrano.rake

edit deploy.rb
And initialize user, application, repository…

set :use_sudo, false
set :user, ‘psq’
set :application, “domain.net”
set :repository, “svn+ssh://domain.net/home/#{user}/svn/domainsvn/trunk”
set :deploy_to, “/home/#{user}/#{application}”

Replace defaulf roles

role :web, application
role :app, application
role :db,  application, :primary => true

Add at the end of deploy.rb. See A better alternative to killall for details.

desc “Restart the FCGI processes on the app server as a regular user.”
task :restart, :roles => :app do
  run “pkill -9 -u #{user} ruby”
end

Now you are ready for the first deployment.

rake remote:exec ACTION=setup

And finally, to deploy:

cap deploy [or]
cap -q deploy (for quiet output)

If you you use “migration”, as you should, to create the tables on the remote host, and every time you update the tables:

rake remote:migrate

This assumed that your app was fully configured to work in your hosting environment. And if you haven’t done that yet, now if the time to do it.

Selecting a rails hosting service

Is there is one thing you could agree with, it is that there are many hosting options for your Ruby on Rail application. And this is a good thing for you. This is good because this means that there are a lot of companies competing for your business.

But it can be easy to get lost in this multitude of offers. So you need to define a selection process before you begin. Write down the criteria that you find important. And as you do your research, that list may change, and that’s ok. This is only a starting point. If you change that list too much, this may be warning flag that you are getting influenced too much but what you are reading.

To help you get started, here’s the list I used when selecting a hosting service:

rails support: that’s the main reason you are looking for a hosting solution. So get the best you can get! This one almost trumps all the others. Ideally you want to find someone that has had quite a bit of experience with rails, and has had a chance to fine tune their systems over time. You also want to make sure they offer more than just plain CGI, something like FastCGI, or FCGI, or even offer LightTPD support. If you don’t have to set it up, any of these will do. In my experience, it is not so important that they provide the latest gems and rails versions as you are better off freezing your gems.

Subversion support: to use Capistrano, this is something which is going to be helpful. You may be able to get CVS working, but subversion is a much better solution overall.

Capistrano support: with ssh and svn, you should be good
Price: Price matters, but most offerings are in the same ballpark, making this secondary. Get something you are comfortable with.

Disk space: you need enough to get your application running. If you envision something with a lots of graphics, sounds or movies, then you will need a lot.

Bandwidth: same as for disk space. You can start small to keep the price down, and most hosting companies will let you upgrade to their next offering, which generally gives you more bandwith, and only charge you the price difference.

Number of domains: how many domains do you really need? 5 to 10 should be more than you need. The thing you really need is the ability to have real domains, without some sort of redirection or frame redirecting to a subdirectory to your main domain.

Number of subdomains: I would not settle for less than an unlimited domain.
Number of databases: you only generally need just 1 or 2 for your application, but why you be charged by the database? They already limit the disk space and the bandwidth. So you’ll get the more serious ones by selecting one that doesn’t limit you.

Backup: once your application reaches production state, you need backups (trust me on that one, you don’t want to get caught without a backup). Site5 has a very nice feature where you get to restore your onw backups whenever you want.

Statistics: you need at least decent statistics. although you may feel the need to use a specialized service, such as Google Analytics, SiteMeter, or more analytics options which will give you a lot more details that what most hosting services give you.

SSH access: this one is a must. To run Capistrano, you need this. Plus this generally comes with ftp access, you get to run rails by hand if necessary, etc.
Email: that’s a no brainer, and I would just look for a good spam solution to go with that.

Excellent uptime: 99.9… or so. You can only go with what the vendor claims. If they are willing to back it with some refund, then they really mean it.
Moneyback: all the serious hosting company will let you try it for at least a month. To weed out the less serious, insist on 60 days or more.

Once you’ve defined your list of criteria, do some research, use google, ask your friends, look for what other people are using.

Create a spreadsheet where you list the various plans for each hosting company with some notes on each criteria.

Very quickly, the top 2 or 3 will start to emerge. Then you can dig a bit deeper, look for what others are saying, look to see if there are a lot of people complaining. For the price, you may even want to give your top 2 or 3 a test drive and see for yourself.

Good luck!

Freeze all your ruby gems on a shared host

Things started to go downlhill when I had to check back on a previous article I had written about (Allowing full access to a sub directory in Apache Server) and my server would just hang!
Well, not a problem, let’s just try to hit the refresh key, hmmm, nothing. Ok, for good measure, let’s hit the button, just to be sure. Hmmm, still nothing.
Ok, let’s check out the logs, started from the apache logs.

[Tue Mar 28 21:04:31 2006] [error] [client 66.249.66.226] FastCGI: incomplete headers
(0 bytes) received from server “/home/psq/blog.nanorails.com/current/public/dispatch.fcgi”

Ok, yep, something’s wrong. Next, let’s hit the production.log. Nothing useful.

Next, a trick I learned before (aren’t you glad it is not your first time troubleshooting FastCGI?). Let’s call public/dispatch.fcgi directly:

/usr/local/lib/site_ruby/1.8/rubygems.rb:194:in `report_activate_error’:
    RubyGem version error: activerecord(1.13.2 not = 1.14.0) (Gem::LoadError)
    from /usr/local/lib/site_ruby/1.8/rubygems.rb:136:in `activate’
    from /usr/local/lib/site_ruby/1.8/rubygems.rb:162:in `activate’
    from /usr/local/lib/site_ruby/1.8/rubygems.rb:161:in `each’
    from /usr/local/lib/site_ruby/1.8/rubygems.rb:161:in `activate’
    from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:23:in `require’
    from ./../config/boot.rb:14
    from ./../config/environment.rb:8:in `require’
    from ./../config/environment.rb:8
    from ./dispatch.fcgi:21:in `require’
    from ./dispatch.fcgi:21

Ah ha! Bingo. What does it all mean, though?

It has been hard to miss that Rails 1.1 is not officially out. Yeahh!!! I wonder whether Dreamhost (aff) has maybe, just maybe, decided to upgrade.

gem list|grep rails

Ah ha! again. Yes, rails is is now 1.0 and 1.1. So I futz a little bit to try to freeze the gems manually, to not avail :(. So I go home, and fortunately, thanks to Capistrano, I have a full copy on my home machine! After doing a little reading, I figure the solution has to be:

rake freeze_gems

So first things first, I get home, rush to my machine, run the magic command, then run what was going to solve all the recent woes:

cap deploy -q

and hit the refresh button…
Duh! Still doesn’t work. Major Bummer!

Next step is to get a copy of all my gems (for typo):

 cd vendor/rails
 gem unpack activerecord
 gem unpack activesupport
 gem unpack actionpack
 gem unpack actionmailer
 gem unpack actionwebservice
 mv activerecord-1.13.2/ rails/
 mv actionmailer-1.1.5/ actionmailer
 mv actionpack-1.11.2/ actionpack
 mv actionwebservice-1.0.0/ actionwebservice
 mv activerecord-1.13.2/ activerecord
 mv activesupport-1.2.5/ activesupport

Your versions may vary depending on your install.

Then, committed everything, and redeployed.

and Ta Da! everything’s now back to normal! Phew…

The moral of the story, it that wasn’t clear already is:

Do not rely on the gems installed on your shared host!
Make sure your freeze all your gems

And I can worry on my own time to upgrade to rails 1.1 in my production environmment.

Update about 2 hours later:
Assuming you can run rake (which I couldn’t because of some broken dependency), an other method to lock down to rails 1.0 is to use:
rake freeze_edgeREVISION=3303

this assumes that’s you are using rails directly from svn already.

Update about 18h later:
An other solution is to lock down the versions of the gems you use in environment.rb using what suggested on Ruby On Rails Wiki. Thank you, Miles Barr for the tip!

Upgrading from SwitchTower to Capistrano

Upgrading/switching from SwitchTower to Capistrano is easy if you follow this recipe (for linux):

sudo gem uninstall switchtower (remove all versions)
sudo gem install capistrano

And for each of your projects:

cap -A .   # don’t forget the period, and keep your deploy.rb
rm lib/tasks/switchtower.rake
svn rm lib/tasks/switchtower.rake
svn add lib/tasks/capistrano.rake
svn commit -m “Capistrano upgrade”

A better alternative to killall

On my host, severall other users are running other rails applications.

So, when using “rake deploy” while using Capistrano (used to be called SwitchTower before someone objected in infringed on their trademark), the default “killall -9 dispatch.fcgi” is trying to kill other processes that do not belong to me. This creates a problem near the end of the deploy command and it returns a failed status. In this case this is harmless, but… your brain has a tendency to learn to ignore errors when running deploy. Next time you get a real error, it might take you a while to realize that the error wasnt caused by the “killall” command. There is a better alternative where you can filter on the user: pkill.

So in deploy.rb, I’ve replace the

run “killall -9 dispatch.fcgi”

by

run “pkill -9 -u #{user} ruby”

on my config, the processes don’t show up as dispatch.fcgi, but as ruby dispatch.fgci

And, now, bliss is upon us:”rake deploy” completes with no error

Once I get more than one app hosted, I’ll figure out how to get Reaper to work.

uninitialized constant SwitchTower (Capistrano?)

I did setup this blog (using the most excellent typo if you need to ask). The next step was to setup switchtower, and you guessed it, it almost worked. Here’s why.

Followed the directions to get it going and was ready to type my first command:

rake –trace remote_exec ACTION=setup

yeah, that would be too easy if it worked, wouldn’t it. Instead of the expected output, I get the very impolite:

** Invoke remote_exec (first_time)
** Execute remote_exec
rake aborted!
uninitialized constant SwitchTower
…/activesupport-1.2.5/lib/active_support/
dependencies.rb:200:in `const_missing’

I mean, I did not mean to be rude, so why is it doing this?

Sorry I can’t give credit to where credit is due (shame on me for not putting the info down at the time. Now that this is site is up and running, I can capture the next problem blow by blow as it happens). If you know who should get the credit, drop me a note. Anyway, here’s the solution.

in lib/taks/switchtower.rake replace


    begin
      require 'rubygems'
    rescue LoadError
      # no rubygems to load, so we fail silently
    end

    options = actions.last.is_a?(Hash) ? actions.pop : {}
to:

    begin
      require 'rubygems'
    rescue LoadError
      # no rubygems to load, so we fail silently
    end

    require 'switchtower/cli'

    options = actions.last.is_a?(Hash) ? actions.pop : {}

Incidentally, I did setup typo directly from svn to get the tagging extension builtin. And to use SwitchTower, I then commited this into my own subversion repository. This might get interesting the day I want to upgrade. We’ll keep this story for an other day.