Daemonizing a Ruby Script in Rails
This took way longer than it should have, so I thought I’d jot down what I did so it might take less time next time.
1. Install the daemons gem
sudo gem install daemons
2. Presumably you have a script that looks something like this already
#!/usr/bin/env ruby require File.dirname(__FILE__) + "/. ./config/environment" SchedulerDaemon.new.run
This is a scheduler script that lives in the scripts directory of a rails project.
3. You’re going to take this code and wrap it in daemon stuff, like so
#!/usr/bin/env ruby RAILS_ROOT = File.expand_path(File.dirname(__FILE__) + '/. .') require 'rubygems' gem 'daemons' require 'daemons' Daemons.run_proc("scheduler", :log_output => true, :dir_mode => :normal, :dir => "#{RAILS_ROOT}/log") do require File.join(RAILS_ROOT, "config/environment") SchedulerDaemon.new.run end
The really hard part for me was debugging it. Which meant figuring out how to get logging going. With this code, you can just tail “log/scheduler.output” and see the contents of any puts in the code. Once I started doing that, everything else was easy.
RAILS_ROOT has to be set first, because daemons changes the current working directory. Also, I use the log dir, because it’s shared by capistrano, so I can deploy, then stop / start my scheduler and not worry about losing my first pid file – plus that’s where logs are supposed to go.
4. To make my life just a little easier, I also added some debugging statements
Daemons.run_proc("scheduler", :log_output => true, :dir_mode => :normal, :dir => "#{RAILS_ROOT}/log") do begin require File.join(RAILS_ROOT, "config/environment") puts "starting scheduler at #{Time.now} for #{RAILS_ENV}" SchedulerDaemon.new.run ensure puts "ending scheduler at #{Time.now}" end end
This was actually pretty easy, and next time it will take 5 minutes to create a daemon. Nice gem.