如何使用ActiveJob设置Sidekiq的重试次数?

时间:2015-10-15 01:43:53

标签: sidekiq rails-activejob

从Rails API,我发现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'

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 }

但似乎不太好。

7 个答案:

答案 0 :(得分:16)

您也可能对使用serializedeserialize 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

here获取。

答案 1 :(得分:11)

你做不到。如果您想使用Sidekiq特定的东西,您需要使用Sidekiq特定的API。 ActiveJob不会暴露Sidekiq的重试机制。

答案 2 :(得分:10)

从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

您还可以设置常量等待间隔或指数等待策略,如docs中所述。

答案 3 :(得分:2)

请参阅here Sidekiq的默认值。属性retry“接受”布尔值,而不是您所假设的数字。

从active_job合并到Rails,other file可以看到retry再次接受重试次数。

documentation says那么,如果作业重试,您可以定义每个作业。

我还尝试查找config/sidekiq.yml文件是否可以接收此号码,而且似乎不能。

最后,

  

如果你没有在25次重试(大约21天)内修复错误,Sidekiq将停止重试并将你的工作转移到Dead Job Queue。您可以使用Web UI在接下来的6个月内随时手动修复错误并手动重试作业。

答案 4 :(得分:2)

有一个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 middleware

首先定义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

答案 5 :(得分:1)

仅供参考,此问题已在Sidekiq 6.0发行版中得到修复。您可以在此处查看更改日志:https://github.com/mperham/sidekiq/blob/master/Changes.md

但是基本上,您可以通过使用选项哈希调用sidekiq_options来传递相同的选项。谢谢Mike Perham。

答案 6 :(得分:-1)

如果你只是使用sidekiq,nerver改变后端,猴子补丁可以帮助你

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

快乐编码