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:
- 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.logdisplays anything sent to
$stderr, from what I can tell. The third,
BackgrounDRb_11006_debug.logdisplays 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.
- Generate a worker.
- Write the code your worker needs to do:
You may notice two things here. Every worker has a
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.
- In the controller action where you want to poll, grab the status of the worker.
This will return whatever object you set to the current status of
the worker using
There’s the basics for getting started with BackgrounDRb. Happy background tasking!