Rails3 on joyent shared (rvm way) - Followup

In my last post I wrote about installing rails3 on ruby 1.8.7 on a joyent shared accelerator. After finishing up my install an restarting my new app/toy/site I noticed a couple things.

On Ruby versions

Ruby 1.8.7 works whether its p299 or p302, the thing that fails is net-ssh with it's weird relocation error.

Ruby 1.9.x doesnt compile, period.

On deploying the production environment

Joyent recommends 2 ways of setting up a production environment on its shared environment:
  • using mongrel
  • using lighttpd
Now, I played with lighttpd back in v2.x, and found it hard to keep running, si I wanted to try mongrel.

Plainly put, I am out of luck: mongrel even 1.2.0pre doesn't work well with rails3. it seems it integrates at a low level in the core rails stack. Except that there were massive changes in the rails3 stack with the inclusion of rack as the core of the stack. As a result some file/class called "dispatcher" is missing and trying the normal mongrel_rails start command just fails with the error shown below:
jean@xps:~/dev/rails/giftr$ mongrel_rails start
** Starting Mongrel listening at
** Starting Rails with development environment...
/home/jean/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc2/lib/active_support/dependencies.rb:239:in `require': no such file to load -- dispatcher (LoadError)
 from /home/jean/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc2/lib/active_support/dependencies.rb:239:in `block in require'
 from /home/jean/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc2/lib/active_support/dependencies.rb:225:in `block in load_dependency'
 from /home/jean/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc2/lib/active_support/dependencies.rb:591:in `new_constants_in'
 from /home/jean/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc2/lib/active_support/dependencies.rb:225:in `load_dependency'
 from /home/jean/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0.rc2/lib/active_support/dependencies.rb:239:in `require'
 from /home/jean/.rvm/gems/ruby-1.9.2-p0/gems/mongrel-1.2.0.pre2/lib/mongrel/rails.rb:148:in `rails'
 from /home/jean/.rvm/gems/ruby-1.9.2-p0/gems/mongrel-1.2.0.pre2/bin/mongrel_rails:116:in `block (2 levels) in run'
 from /home/jean/.rvm/gems/ruby-1.9.2-p0/gems/mongrel-1.2.0.pre2/lib/mongrel/configurator.rb:149:in `call'
 from /home/jean/.rvm/gems/ruby-1.9.2-p0/gems/mongrel-1.2.0.pre2/lib/mongrel/configurator.rb:149:in `listener'
 from /home/jean/.rvm/gems/ruby-1.9.2-p0/gems/mongrel-1.2.0.pre2/bin/mongrel_rails:102:in `block in run'
 from /home/jean/.rvm/gems/ruby-1.9.2-p0/gems/mongrel-1.2.0.pre2/lib/mongrel/configurator.rb:50:in `call'
 from /home/jean/.rvm/gems/ruby-1.9.2-p0/gems/mongrel-1.2.0.pre2/lib/mongrel/configurator.rb:50:in `initialize'
 from /home/jean/.rvm/gems/ruby-1.9.2-p0/gems/mongrel-1.2.0.pre2/bin/mongrel_rails:86:in `new'
 from /home/jean/.rvm/gems/ruby-1.9.2-p0/gems/mongrel-1.2.0.pre2/bin/mongrel_rails:86:in `run'
 from /home/jean/.rvm/gems/ruby-1.9.2-p0/gems/mongrel-1.2.0.pre2/lib/mongrel/command.rb:210:in `run'
 from /home/jean/.rvm/gems/ruby-1.9.2-p0/gems/mongrel-1.2.0.pre2/bin/mongrel_rails:282:in `<top (required)>'
 from /home/jean/.rvm/gems/ruby-1.9.2-p0/bin/mongrel_rails:19:in `load'
 from /home/jean/.rvm/gems/ruby-1.9.2-p0/bin/mongrel_rails:19:in `<main>'
This problem is not joyent specific though (and the captured output comes from my dev station hence the ruby 1.9.x, but I have the exact same stack trace on the joyent shared.

Since mongrel is trying to keep backward compatibility with all versions of rails we are in a tight spot. Defects already exist about this in both rails and mongrel, but no solution in sight for the moment (and this is way over my head for now) :
At the same time, using rails server works like a charm starting up mongrel. I am not sure what the difference is to be honnest.

The deploy solution which works for me

In the meantime, starting rails server seems to work fine.Therefore, here is what I did, found a stop script somewhere on the net (sorry I don't remember where) which works fine:
#!/usr/bin/env bash 

if [ $# -ne $EXPECTED_ARGS ]
  echo "Usage: `basename $0` {pid_file}"
  exit $E_BADARGS

if [ -f $1 ]
  cp $1 $1.stopping
  cat $1 | xargs kill
  mv $1.stopping $1.stopped 
  echo "Usage: `basename $0` {pid_file}"
  exit $E_BADARGS
combined with a tweaked deploy.rb recipe to both link the bundler gem folder and the database config file, and to use my scripts :
set :application, "giftr"
set :repository,  "git@github.com:jeantil/giftr.git"

set :scm, :git # Or: `accurev`, `bzr`, `cvs`, `darcs`, `git`, `mercurial`, `perforce`, `subversion` or `none`

set :deploy_to, "/users/home/#{user}/domains/giftr.byjean.eu/apps/giftr"

#role :web, "#{host}.joyent.us"                          # Your HTTP server, Apache/etc
#role :app, "#{host}.joyent.us"                          # This may be the same as your `Web` server
#role :db,  "#{host}.joyent.us", :primary => true # This is where Rails migrations will run

server "#{kemp}.joyent.us", :app, :web, :db, :primary => true
set :user, "#{user}"
set :use_sudo, false
# If you are using Passenger mod_rails uncomment this:
# if you're still using the script/reapear helper you will need
# these http://github.com/rails/irs_process_scripts
set :port_number, "#{portnum}"  

namespace :deploy do

  task :start, :roles => :app do
    run "cd #{deploy_to}/current; rails s -e production -p #{port_number} -d -P #{deploy_to}/shared/pids/giftr.pid"
    run "echo \"WEBSITE HAS BEEN STARTED\""
  task :stop, :roles => :app do
    run "cd #{deploy_to}/current; script/stop  #{deploy_to}/shared/pids/giftr.pid"
    run "echo \"WEBSITE HAS BEEN STOPPED\""    
  task :restart, :roles => :app do
    run "cd #{deploy_to}/current; script/stop  #{deploy_to}/shared/pids/giftr.pid ; rails s -e production -p #{port_number} -d -P #{deploy_to}/shared/pids/giftr.pid"
  after 'deploy:update_code', 'bundler:bundle_new_release'

namespace :bundler do
  task :create_symlink, :roles => :app do
    shared_dir = File.join(shared_path, 'bundle')
    release_dir = File.join(current_release, '.bundle')
    run("mkdir -p #{shared_dir} && ln -s #{shared_dir} #{release_dir}")

  task :bundle_new_release, :roles => :app do
    run "cd #{release_path} && bundle install --without test"
  after "bundler:bundle_new_release", :link_production_files

# database.yml task
desc "Link in the production database.yml"
task :link_production_files do
  run "ln -nfs #{deploy_to}/shared/config/database.yml #{release_path}/config/database.yml"
Obviously, you will want to replace #{host}, #{user} and #{portnum} with the appropriate values for your host.


Rails3 on joyent shared (rvm way)

Here is the story of my attempts to get a rails3 app to run on a shared account @joyent.


First note the following:
- The app I want to run there is a toy I made mostly for myself and for fun but I would still like to have it on a 'real' server
- I own a lifetime joyent account (back when it was textdrive)
- I didn't upgrade to a private accellerator back then cuz I was short on cash
- The shared account sits mostly idle and I don't want to shell out monthly money for a toy app


I got the app working once using rvm and installing ruby-1.8.7-p299.
Before installing rvm you need to make sure it can find all the tools it needs. Many gnutools are defined as aliases in your .bashrc, rvm doesn't like that. the best way is to
[~] mkdir ~/bin
[~] cd bin
[~] ln -s /usr/local/bin/gdiff diff
[~] ln -s /usr/local/bin/gfind find
[~] ln -s /usr/local/bin/ggrep grep
[~] ln -s /usr/local/bin/gmake make
[~] ln -s /usr/local/bin/gpatch patch
[~] ln -s /usr/ucb/ps ps
[~] ln -s /usr/local/bin/gsed sed
[~] ln -s /usr/ucb/whoami whomai
[~] echo 'export PATH=$HOME/bin:$PATH' >> .bashrc

Make sure you logout / log back in

Installing rvm

From there, installing rvm is pretty straightforward following the installation guide works just fine:
[~] bash < <( curl http://rvm.beginrescueend.com/releases/rvm-install-head )
The next step the rvm install guide recommends is to put
[~] echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm"'>> .bashrc  # This loads RVM into a shell session.
I put it in bashrc as I wanted to have it for non interactive shells too (running rails and such).

Installing ruby

At the time of my first install, I didn't have a problem but with the recent version of rvm I recommend making sure that .rvm/gemsets/ruby/1.8.7/global.gems points to bundler --pre and doesnt force any kind of version.
[~] rvm install ruby-1.8.7 
which installed ruby-1.8.7-p299 (yes this is important)

Installing gems

I recommend you pre-install your gems. Bundler can use a lot of memory and go over the shared account limits. Manually installing the biggest gems first works just fine
[~] gem install rails --pre --no-ri --no-rdoc
[~] gem install bundler --no-ri --no-rdoc
[~] gem install sqlite3-ruby --no-ri --no-rdoc
[~] gem install capistrano --no-ri --no-rdoc
[~] gem install webrat --no-ri --no-rdoc
This would do it for me, bundler works fine after that.

What did _not_ work for me


installing ruby-1.9.2 fails on compilation with a link error, from what I understand opensolaris linker has a bug where it doesn't compile some bit of ruby correctly and makes ruby crash seemingly at random. To avoid random crashes ruby developpers added a test called bug-3662 which tried to link a lib called bug.so to detect the bug. I wasn't able to go any further.

Actually a joyent admin had a look into it and proposed a solution


on either ruby-1.8.7-p299 or 1.8.7-p302 capistrano dies instantly with :
/users/home/user/.rvm/rubies/ruby-1.8.7-p299/lib/ruby/1.8/i386-solaris2.11/openssl.so: ld.so.1: ruby: fatal: relocation error: file /users/home/user/.rvm/rubies/ruby-1.8.7-p299/lib/ruby/1.8/i386-solaris2.11/openssl.so: symbol EC_GROUP_new_curve_GF2m: referenced symbol not found - /users/home/user/.rvm/rubies/ruby-1.8.7-p299/lib/ruby/1.8/i386-solaris2.11/openssl.so (LoadError)
I assume this is linked with ruby 1.9.2 not compiling. Hopefully joyent will upgrade the environment and fix the linker... In the meantime, cap deploy works from my laptop