如何使用 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】:
您也可能对使用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
从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