Using Delayed::Job with Juggernaut
So for this top secret project I’m working on with @TopherBook, I’ve been looking into using background jobs to handle some long-running tasks that are non-essential to the user experience. I researched a few different options including BackgrounDRb, Background::Job and Delayed::Job. Eventually, I decided on using Delayed::Job because it’s simple, allows for multiple workers running on one machine, and requires little setup work.
A very well written tutorial by Adam Wiggins on using Delayed::Job to create a queue-backed feed reader was a great resource for helping me get started with Dj (Part 1, Part 2). However, there are two things that I don’t like about his implementation. First, it isn’t XHTML Strict valid - and as we all know I’m a bit OCD about valid code. And second, he is using a polling method to check whether the background job has completed.
For my project, using client-side polling isn’t going to cut it. I need to use some sort of server-side push method like Juggernaut.
As a proof of concept test, I forked Adam’s qfeedreader example application and replaced his client-side polling with the server-side push from Juggernaut. Surprisingly, the switch was actually pretty simple. The most difficult thing to figure out was how to execute Juggernaut actions after the completion of a job.
I assumed that I could execute any Juggernaut actions from the “perform” method (check the Delayed::Job README for info on “perform”). But for some reason, the javascript I fired off with Juggernaut wasn’t getting back to the client. After some experimenting, I discovered that any Juggernaut call I made before or after the “perform” method fired and was evaluated as expected.
So to make it work in my application, I tweaked the Delayed::Job#invoke_job method by adding callbacks to “before_perform” and “after_perform” on the payload_object:
def invoke_job payload_object.before_perform if payload_object.respond_to? :before_perform payload_object.perform payload_object.after_perform if payload_object.respond_to? :after_perform end
To take advantage of these callbacks, I just added the methods to the object for which “perform” is defined:
def after_perform
Juggernaut.send_to_client("update_feed('#{id}')", 1)
end
With these callbacks in place, and a few tweaks to the related javascript and views, the application was now updating the view via server-side push instead of client-side pull.
To test the example application for yourself, just clone the code from my repository:
git clone git://github.com/whtt-eric/qfeedreader.git
In order to use Juggernaut, you must install the following gems:
sudo gem install json sudo gem install eventmachine sudo gem install juggernaut
Make sure to update the database.yml file and run the migrations:
cp config/database.yml.example config/database.yml rake db:migrate
Next, start the Juggernaut server, the application server and a Delayed::Job worker:
juggernaut -c juggernaut.yml ruby script/server rake jobs:work
Now point your browser to http://localhost:3000. You should see a confirmation message saying ‘Juggernaut Connected on localhost:5001′. If you’re using Firebug it will appear in the console otherwise it will appear as an alert on the page.
Finally, add a few RSS feeds using the form on the page. To refresh the feeds, just click the “refresh” link.
Comments are closed.