At Avvo we wanted to add some metrics and logging to our background job
processing. We're using Resque, so it wouldn't take much to write a module to
perform to do the logging. After investigating the new
ActiveJob abstraction in Rails, we decided there would be benefits to switching.
What does ActiveJob do?
ActiveJob is built into Rails, and provides a common interface for background jobs. It also adds callback support around enqueuing and performing jobs. By default this is used to add logging to your jobs.
Coming from Resque
Plain Resque was a good starting point years ago, but these days we expect more from our libraries. There's no logging and no metrics hooks. By switching to ActiveJob we get all that for free. Plus it might make switching to Sidekiq easier.
Remember to keep in mind during upgrading that you may have job in the queue
when you deploy your new ActiveJobified code. Because of this, we want to keep
the old jobs around, and have them call the new ActiveJob code. Just have old
self.perform methods instantiate the new job class and call
Mechanics of using ActiveJob
Switching involves a few steps:
- Inherit from
- configure in
ruby config.active_job.queue_adapter = :resque config.active_job.queue_name_prefix = "my_app"
performmethods from class to instance.
- Switch from using
For instance, we'd change the following class:
class OldCsvParser @queue = :csv_parsing def self.perform(filename) # ... do stuff end end
class CsvParserJob < ActiveJob::Base queue_as :csv_parsing def perform(filename) # ... do the stuff end end
and update the original class to just call the new one:
class OldCsvParser @queue = :csv_parsing def self.perform(filename) CsvParserJob.new.perform(filename) end end
Testing with ActiveJob::TestHelper
For instance, if we enqueued a
CsvParserJob from a controller action, our
test might look like this:
class CsvParsingControllerTest < ActiveSupport::TestCase test "enqueues the job to parse the csv" do filename = "/path/to/csv/file.csv" assert_enqueued_with(job: CsvParserJob, args: [filename]) do post :create, filename: filename end end end
Integration with ResqueScheduler
Resque::Scheduler enqueues jobs
Resque. You'll need to either change that behavior or wrap jobs in the
schedule with a JobWrapper.
Luckily the latter work has already been done, and using the gem ActiveScheduler will wrap the jobs so callbacks are called.
Installation is a snap, just follow the directions in the project's readme to
Downsides: ResqueWeb only shows JobWrapper job classes
Due to the ActiveJob
JobWrapper viewing the running jobs in resque-web will
no longer show the class of actual job running on the dashboard. Clicking
through and viewing the arguments does show the class. This could be a hassle
if you often view the job queue.
Similarily, the Schedule tab in resque-web is a little cluttered. But still readable.