Thursday, December 13, 2007

backgrounDRb and RubyOnRails

Lately I've been running into the situation where I need to have a process running to periodically handle some task like sending emails or other bulk processing. Well, if you run into that situation I highly recommend using a very nice plugin by Ezra called backgrounDRb.

BackgrounDRb is ruby server that allows you schedule jobs to run at various intervals. Sounds like a good use for cron eh? Well, I could have used cron and wrote a script that loaded the rails environment in order to use my models but wait, why bother? BackrounDRb loads the rails environment and does the scheduling. I don't have to do anything but write my standard RubyonRails style lib. Very nice.

Here's a quick rundown on what you need to do to get this running.

#install the plugin
script/plugin install http://svn.devjavu.com/backgroundrb/trunk

#add backgroundrb.yml to your config dir
#add backgroundrb to your scripts dir
#create lib/workers dir
#create test/bdrb_test_helper.rb
#all of the above done by:
rake backgroundrb:setup

That was super easy, and now you're mostly done.
You're backgroundrb.yml will look like:

---
:backgroundrb:
:port: 11006
:ip: localhost

A good start, but here's a sample one that has a little more info:

---
:backgroundrb:
:ip: 0.0.0.0
:port: 11006
:schedules:
:my_process_worker:
:do_process:
:trigger_args:
:start: <%= Time.now + 5.seconds %>
:end: <%= Time.now + 1.month %>
:repeat_interval: <%= 2.minutes %>

So, what is my_process_worker and do_process? Well that's your class and method you want to run. The start, end and repeat_interval fields are self explanatory.

The my_process_worker will correspond to a file in your lib/workers directory called my_process_worker.rb.

class MyProcessWorker < BackgrounDRb::MetaWorker
set_worker_name :my_process_worker

def create(args = nil)
# this method is called, when worker is loaded for the first time
end

#this is the method referred to in the backgroundrb.yml
def do_process
1.upto(10) do |i|
puts i
end
end
end

Okay, so you will have a lot more to do in the do_process method, but you get the point. By the way, do_process is just an example, it holds no special meaning to backgrounDRb.

So, the only thing that wasn't super obvious to me was, how do you start the process? Well, it's easy:

#to start
script/backgroundrb start

#to stop
script/backgroundrb stop

This loads your backgroundrb.yml file and, in the example, will call the MyProcessWorker do_process method.

The only thing left really is a little Capistrano example. Here are some tasks for you:

desc "Start the backgroundrb server"
task :start_backgroundrb, :roles => :app do
run "cd #{release_path} && ./script/backgroundrb start"
#you can pass in a rails_env like
#run "cd #{release_path} && RAILS_ENV=production nohup ./script/backgroundrb start"
end

desc "Stop the backgroundrb server"
task :stop_backgroundrb, :roles => :app do
run "cd #{release_path} && ./script/backgroundrb stop"
end

desc "Restart the backgroundrb server"
task :restart_backgroundrb, :roles => :app do
stop_backgroundrb
start_backgroundrb
end

Just call the restart_backgroundrb task at the end of your deployment cycle, typically after a mongrel restart.

By the way, it's not just for use with RubyOnRails. You can use backgrounDRb for any of your Ruby programming needs.

Thanks to Greg for his review and help with this post.

0 comments: