Retrying ActiveJob
I like ActiveJob. One missing feature is the ability to retry when a job fails. Fortunately, this is quite easy to add:
module ActiveJobRetriesCount
extend ActiveSupport::Concern
included do
attr_accessor :retries_count
end
def initialize(*arguments)
super
@retries_count ||= 0
end
def deserialize(job_data)
super
@retries_count = job_data['retries_count'] || 0
end
def serialize
super.merge('retries_count' => retries_count || 0)
end
def retry_job(options)
@retries_count = (retries_count || 0) + 1
super(options)
end
end
class ImageDownloader::Worker < ActiveJob::Base
include ActiveJobRetriesCount
rescue_from ImageDownloader::TimeoutError do |exception|
if exception.code == 0
# just retry the download in 5 minutes
# tolarate up to 5 failures
retry_job wait: 5.minutes if retries_count > 5
else
fail exception
end
end
def perform(url)
ImageDownloader.download(url)
end
end
Here is a simple test for the ActiveJobRetriesCount
.
require 'spec_helper'
describe ActiveJobRetriesCount do
class RetriesTestClass
end
class RetriesTestError < StandardError
end
class RetriesTestWorker < ActiveJob::Base
include ActiveJobRetriesCount
rescue_from RetriesTestError do
retry_job wait: 5.minutes if retries_count < 5
end
def perform
RetriesTestClass.do_something(retries_count)
end
end
it 'handles retries counts', active_job: :inline do
allow(RetriesTestClass).to receive(:do_something).and_raise RetriesTestError
expect { RetriesTestWorker.perform_later }.not_to raise_error
expect(RetriesTestClass).to have_received(:do_something).with(5)
expect(RetriesTestClass).not_to have_received(:do_something).with(6)
end
end
If you are not on Rails 5, you would need the following code:
if ActiveJob::Base.method_defined?(:deserialize)
fail 'This no longer needed.'
else
module ActiveJob
class Base
def self.deserialize(job_data)
job = job_data['job_class'].constantize.new
job.deserialize(job_data)
job
end
def deserialize(job_data)
self.job_id = job_data['job_id']
self.queue_name = job_data['queue_name']
self.serialized_arguments = job_data['arguments']
end
end
end
end
For more advanced features – check out ActiveJob::Retry.