Starting ferret at reboot using Capistrano

Posted by jeff

I like using Ferret and acts_as_ferret to add full-text search to my models in Rails in a database-independent way. I’ve had a very difficult time getting this to work smoothly with my deployment process because the ferret server needs to be run in a separate process.

Every time the server reboots, you need to start the ferret server, and everytime you deploy your app you need to restart the ferret server. You can go to the acts_as_ferret site to get more information about deployment strategies, but here’s what’s been working for me for a while now.

First, you need to create a startup script that can be run on boot. I’ve taken mine from the railsmachine tutorial, but you can also use the one from the acts_as_ferret tutorial. Mine looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# located in config/templates/ferret_ctl.erb
#!/bin/bash
#
# This script starts and stops the ferret DRb server
# chkconfig: 2345 89 36
# description: Ferret search engine for ruby apps.
#
# save the current directory
CURDIR=`pwd`
PATH=/usr/local/bin:$PATH

RORPATH="<%= current_path %>"

case "$1" in
  start)
     cd $RORPATH
     echo "Starting ferret DRb server."
     RAILS_ENV=<%= rails_env %> script/ferret_start
     ;;
  stop)
     cd $RORPATH
     echo "Stopping ferret DRb server."
     RAILS_ENV=<%= rails_env %> script/ferret_stop
    ;;
  *)
     echo $"Usage: $0 {start, stop}"
     exit 1
     ;;
esac

cd $CURDIR

Next, add the following capistrano tasks to your deploy.rb file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# =============================================================================
# FERRET
# =============================================================================
set :ferret_script_name, "ferret_#{application}_ctl"
set :ferret_ctl, "/etc/init.d/#{ferret_script_name}"

namespace :ferret do
  desc "Uploads the ferret startup script"
  task :install, :roles => :app, :only => {:primary => true} do 
    require 'erb'
    upload_path = "#{shared_path}/ferret" 
    template = File.read("config/templates/ferret_ctl.erb")
    file = ERB.new(template).result(binding) 
    put file, upload_path, :mode => 0755
    sudo "cp #{upload_path} #{ferret_ctl}"
    sudo "chmod +x #{ferret_ctl}"
    sudo "/sbin/chkconfig #{ferret_script_name} on"
  end 

  desc "Starts the ferret server"
  task :start, :roles => :app, :only => {:primary => true} do
    sudo "#{ferret_ctl} start"
  end

  desc "Stops the ferret server"
  task :stop, :roles => :app, :only => {:primary => true} do
    sudo "#{ferret_ctl} stop"
  end

  desc "Restarts the ferret server"
  task :restart, :roles => :app, :only => {:primary => true} do
    ferret.stop
    ferret.start
  end
  
  desc "Deletes the ferret startup script"
  task :uninstall, :roles => :app, :only => {:primary => true} do 
    sudo "/sbin/chkconfig #{ferret_script_name} off"
    sudo "rm -rf #{ferret_ctl}"
  end 
  
end
after "deploy:symlink", "ferret:restart"

Now you are ready to deploy – just execute the following commands to get set up with your script:

cap ferret:install
cap deploy

The installation will:

  • Upload your startup script to /etc/init.d and set the correct permissions
  • When you deploy it will restart the drb servers before restarting mongrel

Thanks to the folks at Railsmachine for providing detailed instructions about chkconfig, and the acts_as_ferret folks for providing the drb server.

Comments

Leave a response

  1. Johannes FahrenkrugJune 03, 2008 @ 11:05 AM

    Thank you so much for this! This was exactly what I was looking for.

  2. PAcoJune 20, 2008 @ 11:13 PM

    yure great

  3. jonathanSeptember 25, 2008 @ 07:35 PM

    hi jeff

    first off, great script. i used it a couple of months ago and it worked perfectly. now i am trying to use it again and having trouble. here’s what happens”

    when i tried to run the cap:ferret install with the deploy.rb with role

    :app, domain # :primary => true

    i got this error(note: line 54 is the primary true for the app):

    ap ferret:install ./config/deploy.rb:54:in `load’: compile error (SyntaxError) ./config/deploy.rb:54: syntax error, unexpected tSYMBEG, expecting kDO or ‘{’ or ‘(‘ role :app, domain :primary => true ^ from /Library/Ruby/Gems/1.8/gems/capistrano-2.4.3/lib/capistrano/configuration/loading.rb:172:in `load_from_file’ from /Library/Ruby/Gems/1.8/gems/capistrano-2.4.3/lib/capistrano/configuration/loading.rb:89:in `load’ from /Library/Ruby/Gems/1.8/gems/capistrano-2.4.3/lib/capistrano/configuration/loading.rb:86:in `load’ from /Library/Ruby/Gems/1.8/gems/capistrano-2.4.3/lib/capistrano/configuration/loading.rb:86:in `each’ from /Library/Ruby/Gems/1.8/gems/capistrano-2.4.3/lib/capistrano/configuration/loading.rb:86:in `load’ from Capfile:3:in `load’ from /Library/Ruby/Gems/1.8/gems/capistrano-2.4.3/lib/capistrano/configuration/loading.rb:172:in `load_from_file’ from /Library/Ruby/Gems/1.8/gems/capistrano-2.4.3/lib/capistrano/configuration/loading.rb:89:in `load’ ... 7 levels… from /Library/Ruby/Gems/1.8/gems/capistrano-2.4.3/lib/capistrano/cli/execute.rb:14:in `execute’ from /Library/Ruby/Gems/1.8/gems/capistrano-2.4.3/bin/cap:4 from /usr/bin/cap:19:in `load’ from /usr/bin/cap:19

    And when trying to do it without that primary true i simply got:

    `ferret:install’ is only run for servers matching {:roles=>:app, :only=>{:primary=>true}}, but no servers matched

    Do you know why this might be prompting an error.

    thanks in advanced

    jonathan

  4. Isaac SparksNovember 12, 2008 @ 04:45 PM

    o6yhd1r0ed703udg

  5. JanMarch 02, 2009 @ 07:13 PM

    Sorry if this is a stupid question, but I’m a novice. I tried your script, but when I run cap ferret:install I get the follwoing error:

    • executing `ferret:install’ /usr/lib/ruby/gems/1.8/gems/capistrano-2.5.5/lib/capistrano/configuration/namespaces.rb:188:in `method_missing’: undefined local variable or method `rails_env’ for # (NameError) from (erb):18:in `load’ from ./config/deploy.rb:133:in `load’ from /usr/lib/ruby/gems/1.8/gems/capistrano-2.5.5/lib/capistrano/configuration/execution.rb:128:in `instance_eval’ from /usr/lib/ruby/gems/1.8/gems/capistrano-2.5.5/lib/capistrano/configuration/execution.rb:128:in `invoke_task_directly_without_callbacks’ from /usr/lib/ruby/gems/1.8/gems/capistrano-2.5.5/lib/capistrano/configuration/callbacks.rb:27:in `invoke_task_directly’ from /usr/lib/ruby/gems/1.8/gems/capistrano-2.5.5/lib/capistrano/configuration/execution.rb:81:in `execute_task’ from /usr/lib/ruby/gems/1.8/gems/capistrano-2.5.5/lib/capistrano/configuration/execution.rb:93:in `find_and_execute_task’ from /usr/lib/ruby/gems/1.8/gems/capistrano-2.5.5/lib/capistrano/cli/execute.rb:45:in `execute_requested_actions_without_help’ from /usr/lib/ruby/gems/1.8/gems/capistrano-2.5.5/lib/capistrano/cli/execute.rb:44:in `each’ from /usr/lib/ruby/gems/1.8/gems/capistrano-2.5.5/lib/capistrano/cli/execute.rb:44:in `execute_requested_actions_without_help’ from /usr/lib/ruby/gems/1.8/gems/capistrano-2.5.5/lib/capistrano/cli/help.rb:19:in `execute_requested_actions’ from /usr/lib/ruby/gems/1.8/gems/capistrano-2.5.5/lib/capistrano/cli/execute.rb:33:in `execute!’ from /usr/lib/ruby/gems/1.8/gems/capistrano-2.5.5/lib/capistrano/cli/execute.rb:14:in `execute’ from /usr/lib/ruby/gems/1.8/gems/capistrano-2.5.5/bin/cap:4 from /usr/bin/cap:19:in `load’ from /usr/bin/cap:19

    Have not made any changes. to your script. Any ideas would be welcome

  6. JanMarch 02, 2009 @ 07:24 PM

    Ha, figured out my own problem. If I add a line:

    <% rails_env = ‘production’ %> after your path definition, this goes through.

Comment