At Flowdock we’re using Resque to process a bunch of background jobs: Campfire imports, analytics, payments, digest emails and others.
It works great, but I realized it’s not trivial to configure this combination to
- work with Bundler
- be reliable when servers are in inconsistent state
- restart gracefully without interrupting running jobs
So here’s how we’re doing it!
Configuring god
This is actually the part where existing documentation is correct. We have a fairly simple config/app.god, that just loads all the other files:
path = File.expand_path(File.join(File.dirname(__FILE__), 'god'))
God.load "#{path}/*.god"
Check out resque.god and resque_scheduler.god for the full configuration files, but here’s the beef:
God.watch do |w|
w.dir = "#{rails_root}"
w.name = "resque-#{resque_id}"
w.group = 'resque'
w.interval = 30.seconds
w.env = {"QUEUES"=>resque_queues, "RAILS_ENV"=>rails_env, "BUNDLE_GEMFILE"=>"#{rails_root}/Gemfile"}
w.start = "bundle exec rake -f #{rails_root}/Rakefile environment resque:work"
w.log = "#{rails_root}/log/resque-#{resque_id}.log"
…
end
Capistrano uses a different environment than your login shell, so it’s a good idea to define Bundler configuration here.
Configuring Capistrano
When deploying our app, we want to restart workers gracefully: they should be able to finish their on-going tasks first. Also, it needs to work whether god is up or not.
Here’s the configuration (to be included in config/deploy.rb) that I’ve found most reliable:
def try_killing_resque_workers
run "pkill -3 -f resque"
rescue
nil
end
desc "Restart God gracefully"
task "restart_god", :roles => :app do
god_config_path = File.join(release_path, 'config', 'app.god')
begin
# Throws an exception if god is not running.
run "cd #{release_path}; bundle exec god status && RAILS_ENV=#{rails_env} RAILS_ROOT=#{release_path} bundle exec god load #{god_config_path} && bundle exec god start resque"
# Kill resque processes and have god restart them with the newly loaded config.
try_killing_resque_workers
rescue => ex
# god is dead, workers should be as well, but who knows.
try_killing_resque_workers
# Start god.
run "cd #{release_path}; RAILS_ENV=#{rails_env} bundle exec god -c #{god_config_path}"
end
end
after :"deploy:restart", :"deploy:restart_god"
And that’s all folks!