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

Posted

技术标签:

【中文标题】如何使用 ActiveJob 设置 Sidekiq 的重试次数?【英文标题】:How to set retry count for Sidekiq with ActiveJob? 【发布时间】:2016-01-13 07:35:33 【问题描述】:

从 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 

不过好像不太好。

【问题讨论】:

【参考方案1】:

从 Sidekiq 6.0.4 开始,您可以在 ActiveJob 中使用 sidekiq_options 来设置 retry 选项。

【讨论】:

谢谢。 Sidekiq-specific 是什么?你能告诉我如何在 ActiveJob 类中使用它吗? 方法sidekiq_options一人! @MikePerham 这在 v6 中是否随着 Sidekiq::Worker::Options 的引入而改变? 部分重试仍未暴露,但sidekiq_options是一大进步。【参考方案2】:

您也可能对使用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获取。

【讨论】:

【参考方案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

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

【讨论】:

ActiveJob 在 Rails 5 中变得非常方便。感谢您的回答! 从文档中,“如果异常持续引发超过指定的尝试次数,则允许异常冒泡到底层排队系统,该系统可能有自己的重试机制或将其放入等待检查的等待队列。”。这意味着除非您完全禁用 sidekiq 的重试并仅使用 retry_on,否则无法使用它来限制作业的重试次数。 @PulkitGoyal 这是一个很好的观点!据我了解,这项工作最多可以重试 30 次(ActiveJob 5 次,Sidekiq 使用其默认设置再试 25 次)?这会让 IMO 非常混乱,所以最好还是坚持使用 Sidekiq 的特定设置。【参考方案4】:

有一个 activejob-retry gem 可以完成这项工作

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】:

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

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

然后documentation says 是您可以定义每个作业是否重试。

我也试了一下config/sidekiq.yml文件能不能收到这个号码,好像不能。

最后,

如果您在 25 次重试(大约 21 天)内未修复该错误,Sidekiq 将停止重试并将您的作业移至死作业队列。您可以在接下来的 6 个月内随时使用 Web UI 修复错误并手动重试该作业。

【讨论】:

你错了。 “重试”可以是一个数字。 github.com/mperham/sidekiq/wiki/Error-Handling#configuration 您的问题标题为“with ActiveJob”。您发送的 URL 不是来自 ActiveJob。回购的所有者(@MikePerham)也回复说你不能 谢谢。我已将Sidekiq.default_worker_options = retry: 5 添加到我的班级。但似乎工作更糟(一天重试很多次!)。默认重试次数是25,那我不能自定义吗? 查看here RetryJobs 是什么。您添加的代码应该添加到application.rb,而不是您的 ActiveJob 子类。如果这不能按您想要的方式工作,只需将所有工作移至 app/workers/(将文件名后缀重命名为 _worker.rb)并采用标准方式(à lá Rails 3) 谢谢。那如果不想重试怎么办?【参考方案6】:

仅供参考,此问题已在 Sidekiq 6.0 版本中得到修复。你可以在这里查看更新日志:https://github.com/mperham/sidekiq/blob/master/Changes.md

但基本上你可以通过使用你的选项哈希调用sidekiq_options 来传递相同的选项。谢谢迈克·佩勒姆。

【讨论】:

以上是关于如何使用 ActiveJob 设置 Sidekiq 的重试次数?的主要内容,如果未能解决你的问题,请参考以下文章

将 ActiveJob 与 Sidekiq 一起使用与单独使用 Sidekiq 相比的优势

ActiveJob + Sidekiq 6.0.3:如何写入日志文件?

使用 ActiveJob 禁用自动重试,与 Sidekiq 一起使用

使用 Sidekiq 进行活动作业并获取 ActiveJob::DeserializationError

Sidekiq Rails 4.2使用活动作业还是工作者?有什么不同

如何在 Rails 控制台中运行 ActiveJob 进行调试?