From the Rails API, I found ActiveJob can retry_job interval:
my_job_instance.enqueue
my_job_instance.enqueue wait: 5.minutes
my_job_instance.enqueue queue: :imp
You also might be interested in this solution which uses serialize
and deserialize
api to store the number of attempts.
class DeliverWebhookJob < ActiveJob::Base
def serialize
super.merge('attempt_number' => (@attempt_number || 0) + 1)
end
def deserialize(job_data)
super
@attempt_number = job_data['attempt_number']
end
rescue_from(ErrorLoadingSite) do |exception|
retry_job(wait: 10) if @attempt_number < 5
end
def perform(*args)
# raise ErrorLoadingSite if cannot scrape
end
end
Take it from here.
if you just use sidekiq, nerver change backend, monkey patch can help you
module ActiveJob
module QueueAdapters
class SidekiqAdapter
def enqueue(job)
JobWrapper.sidekiq_options job.sidekiq_options_hash if job.sidekiq_options_hash
JobWrapper.sidekiq_retry_in job.sidekiq_retry_in_block if job.sidekiq_retry_in_block
Sidekiq::Client.push(
'class' => JobWrapper,
'wrapped' => job.class.to_s,
'queue' => job.queue_name,
'args' => [ job.serialize ]
)
end
def enqueue_at(job, timestamp)
JobWrapper.sidekiq_options job.sidekiq_options_hash if job.sidekiq_options_hash
JobWrapper.sidekiq_retry_in job.sidekiq_retry_in_block if job.sidekiq_retry_in_block
Sidekiq::Client.push(
'class' => JobWrapper,
'wrapped' => job.class.to_s,
'queue' => job.queue_name,
'args' => [ job.serialize ],
'at' => timestamp
)
end
end
end
class Base
class_attribute :sidekiq_options_hash
class_attribute :sidekiq_retry_in_block
def self.sidekiq_options(opts={})
self.sidekiq_options_hash = opts
end
def self.sidekiq_retry_in(&block)
self.sidekiq_retry_in_block = block
end
end
end
then, you can write like below:
class BaseJob < ActiveJob::Base
sidekiq_options retry: 2, queue: :low
sidekiq_retry_in { |count, _| 3 * count }
def perform; end
end
happy coding
See here the defaults for Sidekiq. The attribute retry
"accepts" a boolean value and not a number as you assumed.
From the merge of active_job into Rails this other file one can see that once again retry
doesn't accept the number of retries.
What the documentation says then is that per job you can define if the job retries or not.
I also tried to find if the config/sidekiq.yml
file can receive this number, and seems like it can't.
Finally,
If you don't fix the bug within 25 retries (about 21 days), Sidekiq will stop retrying and move your job to the Dead Job Queue. You can fix the bug and retry the job manually anytime within the next 6 months using the Web UI.
Since Rails 5.1, there is a built-in way to do this using the retry_on method. It's a general ActiveJob method, so it will work with any queuing backend, not just Sidekiq.
For example, for your specific job you could do:
class SiteScraperJob < ActiveJob::Base
retry_on ErrorLoadingSite, queue: :low_priority, attempts: 5
def perform(*args)
# raise ErrorLoadingSite if cannot scrape
end
end
You can also set a constant wait interval or an exponential wait strategy, as explained in the docs.
There is a activejob-retry gem which does the job
class SiteScrapperJob < ActiveJob::Base
include ActiveJob::Retry.new(limit: 5, strategy: :exponential)
def perform(*args)
# raise ErrorLoadingSite if cannot scrape
end
end
Another option is to use sidekiq middleware:
First define job_options class-method which will be available in the subclasses:
class ApplicationJob < ActiveJob::Base
def self.job_options(options)
@job_options = options
end
def self.get_job_options
@job_options || {}
end
end
Add middleware which reads job_options from the jobs's class and writes them to the job item for sidekiq:
module Sidekiq
class JobOptionsMiddleware
def call(job_wrapper, item, queue, redis_pool)
job = item['args'][0]['job_class'].constantize
job.get_job_options
.each{ |option, value| item[option] = value if item[option].nil? }
yield
end
end
# in sidekiq initializer
Sidekiq.configure_client do |config|
config.client_middleware do |chain|
chain.add Sidekiq::JobOptionsMiddleware
end
end
And finally
class SiteScrapperJob < ApplicationJob
job_options retry: 5
def perform
# your code
end
end
FYI this problem has been fixed in the release of Sidekiq 6.0. You can have a look at the changelog here: https://github.com/mperham/sidekiq/blob/master/Changes.md
But basically you can pass the same options by calling sidekiq_options
with your options hash. Thanks Mike Perham.