BackgrounDRb Matures

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:

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.

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:

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:

Install the plugin. (Read the docs on the site linked above.)

Create the necessary boilerplate.

$ rake backgroundrb:setup

Generate a worker.

$ script/generate worker jump

Write the code your worker needs to do:

classJumpWorker<BackgrounDRb::MetaWorkerset_worker_name:jump_workerdefcreate(args=nil)# this method is called, when worker is loaded for the first timeenddefjive(params)Rockabilly.new(params,logger).wailregister_status:wail_awayendend

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.

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.