Как установить счетчик попыток для Sidekiq с помощью ActiveJob?
Из API Rails я обнаружил, что ActiveJob может retry_job интервал:
my_job_instance.enqueue
my_job_instance.enqueue wait: 5.minutes
my_job_instance.enqueue queue: :important
my_job_instance.enqueue wait_until: Date.tomorrow.midnight
http://api.rubyonrails.org/classes/ActiveJob/Enqueuing.html
Но если я хочу установить счетчик повторов, например Sidekiq's:
include Sidekiq::Worker
sidekiq_options :retry => 5
https://github.com/mperham/sidekiq/wiki/Error-Handling
Как это сделать в этом примере кода?
class SiteScrapperJob < ActiveJob::Base
rescue_from(ErrorLoadingSite) do
retry_job queue: :low_priority
end
def perform(*args)
# raise ErrorLoadingSite if cannot scrape
end
end
Теперь я добавил это в мой класс работы:
Sidekiq.default_worker_options = { retry: 5 }
Но это кажется не очень хорошим.
Ответы
Ответ 1
Вас также может заинтересовать это решение, которое использует serialize
и deserialize
api для хранения количества попыток.
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
Возьми это отсюда.
Ответ 2
Вы не можете. Если вы хотите использовать специфичные для Sidekiq вещи, вам нужно использовать специфичные для Sidekiq API. ActiveJob не выставляет механизм повторной попытки Sidekiq.
Ответ 3
Начиная с Rails 5.1, есть встроенный способ сделать это, используя метод retry_on. Это общий метод ActiveJob, поэтому он будет работать с любым бэкэндом, не только с Sidekiq.
Например, для вашей конкретной работы вы можете сделать:
class SiteScraperJob < ActiveJob::Base
retry_on ErrorLoadingSite, queue: :low_priority, attempts: 5
def perform(*args)
# raise ErrorLoadingSite if cannot scrape
end
end
Вы также можете установить постоянный интервал ожидания или экспоненциальную стратегию ожидания, как описано в документации.
Ответ 4
См. здесь значения по умолчанию для Sidekiq. Атрибут retry
"принимает" логическое значение, а не число, как вы предполагали.
Из слияния active_job в Rails этот другой файл можно увидеть, что еще раз retry
не принимает количество попыток.
Что говорит документация, то это за задание, которое вы можете определить, если задание повторится или нет.
Я также попытался найти, может ли файл config/sidekiq.yml
получить этот номер, и кажется, что он не может.
Наконец,
Если вы не исправите ошибку в течение 25 попыток (около 21 дня), Sidekiq прекратит повторную попытку и переместит вашу работу в Очередь мертвых заданий. Вы можете исправить ошибку и повторить задание вручную в любое время в течение следующих 6 месяцев с помощью веб-интерфейса.
Ответ 5
Существует sidekiq-retry, который выполняет работу
class SiteScrapperJob < ActiveJob::Base
include ActiveJob::Retry.new(limit: 5, strategy: :exponential)
def perform(*args)
# raise ErrorLoadingSite if cannot scrape
end
end
Другой вариант - использовать промежуточное ПО sidekiq:
Сначала определите класс-метод job_options, который будет доступен в подклассах:
class ApplicationJob < ActiveJob::Base
def self.job_options(options)
@job_options = options
end
def self.get_job_options
@job_options || {}
end
end
Добавьте промежуточное программное обеспечение, которое считывает job_options из класса заданий и записывает их в элемент задания для 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
И наконец
class SiteScrapperJob < ApplicationJob
job_options retry: 5
def perform
# your code
end
end
Ответ 6
если вы просто используете sidekiq, backerver сервера обновлений, патч обезьяны может помочь вам
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
тогда вы можете написать, как показано ниже:
class BaseJob < ActiveJob::Base
sidekiq_options retry: 2, queue: :low
sidekiq_retry_in { |count, _| 3 * count }
def perform; end
end
счастливое кодирование