BackgrounDRb Matures

by Sean Cribbs

This week I had to figure out how to offload a really long-running task into the background in one of my Rails apps. I had looked at BackgrounDRb (BackgroundRb? I’m not sure if it uses DRb anymore, and it’s easier to type that way, at least for me.) in the past, but it recently reached 1.0 and got a new lead developer, so I gave it another look. The API has improved and matured and it seems easier to get started. However, there were still a few things I didn’t expect:

  1. It’s best to stick with internal Ruby classes for sending data from your Rails app to a worker. I had created a sort of “presenter” object that would convert an incoming form hash into a useful data structure that I could manipulate when running the worker. My first attempt involved initializing the presenter with the form hash, then sending the presenter to the worker in a method call. I kept getting deserialization errors, even if I did an explicit require. In the end it was just easier to pass the raw hash to the worker and then wrap it in the presenter when it starts working.
  2. Test/Spec/Debug your work as much as you can ahead of time. BackgrounDRb doesn’t automatically reload classes, so when errors occurred, I found myself doing this a lot:
     >> exit
    $ script/backgroundrb stop
    $ script/backgroundrb start
    $ script/console
  1. BackgrounDRb uses three different log files, which can be somewhat frustrating and initially confusing. One, BackgrounDRb_11006.log (where 11006 is the port) displays logger output from your workers. The second, BackgrounDRb_server_11006.log displays anything sent to $stdout or $stderr, from what I can tell. The third, BackgrounDRb_11006_debug.log displays the packets of information being sent across the wire between the client and BackgrounDRb. At one point, I had three terminal tabs open with a tail running for each log file. Ick.

Despite those gotchas, it seems to be much easier to create long-running tasks for your Rails app. I even implemented an Ajax polling mechanism to check the status of a job. Here’s the basic steps:

  1. Install the plugin. (Read the docs on the site linked above.)
  2. Create the necessary boilerplate.
   $ rake backgroundrb:setup
  1. Generate a worker.
$ script/generate worker jump 
  1. Write the code your worker needs to do:
     class JumpWorker < BackgrounDRb::MetaWorker
       set_worker_name :jump_worker
       def create(args = nil)
         # this method is called, when worker is loaded for the first time
       end

       def jive(params)
         Rockabilly.new(params, logger).wail
         register_status :wail_away
       end
     end
   

You may notice two things here. Every worker has a logger object, so I pass that to my class that does the actual work so it can log useful messages. Second, the register_status call sets an object as the current status of the worker. This lets you keep track of progress of the worker from your application.

  1. In your controller, create and invoke your worker. If you want to track progress, make sure to assign a job key that your client can use to poll. I used the current time converted to an integer, which will be enough for my small-usage app.
  @job_key = MiddleMan.new_worker(:worker => :jump_worker, :job_key => Time.now.to_i)
  MiddleMan.worker(:jump_worker,
  @job_key).jive(params[:brian_setzer])
  
  1. In the controller action where you want to poll, grab the status of the worker.
  @status = MiddleMan.worker(:jump_worker,
  params[:job_key].to_i).ask_status
  

This will return whatever object you set to the current status of the worker using register_status.

There’s the basics for getting started with BackgrounDRb. Happy background tasking!

© 2006-present Sean CribbsGithub PagesTufte CSS