工作中的 Sidekiq 重试计数
Posted
技术标签:
【中文标题】工作中的 Sidekiq 重试计数【英文标题】:Sidekiq retry count in job 【发布时间】:2014-05-28 17:40:56 【问题描述】:有没有办法获取当前作业的重试次数?
我希望作业在重试 x 次后停止,而不是崩溃。我想问一下perform方法中的重试次数,如果重试次数等于x,我可以简单地返回。
def perform(args)
return if retry_count > 5
...
end
使用 Sidekiq 2.12。
编辑
我(不是 OP)有同样的问题,但出于不同的原因。如果正在重试该作业,我想进行额外的完整性检查以确保需要该作业,并在由于排队后发生外部更改而不再期望该作业成功时退出重试。
那么,有没有办法获取当前作业的重试次数?当前的答案只建议了您可以绕过需要它或可以从工作之外获得它的方法。
【问题讨论】:
你有什么解决办法吗? 【参考方案1】:这可以通过添加一个 sidekiq 中间件来将 msg['retry_count'] 设置为作业类的实例变量来实现。
添加一个中间件(在 Rails 中,通常是/config/initializers/
文件夹中的一个文件),如下所示:
class SidekiqMiddleware
def call(worker, job, queue)
worker.retry_count = job['retry_count'] if worker.respond_to?(:retry_count=)
yield
end
end
Sidekiq.configure_server do |config|
config.server_middleware do |chain|
chain.add SidekiqMiddleware
end
end
在你的工作中:
include Sidekiq::Worker
attr_accessor :retry_count
def retry_count
@retry_count || 0
end
def perform(args)
return if retry_count > 5
...
end
【讨论】:
中间件类放哪个文件夹?我可以把它放在我放“Sidekiq.configure_server”的地方吗? 为什么我会收到这个错误NoMethodError: undefined method
retry_count=' 对于 #<:extensions::delayedmailer:0x007f9ad8928338>`
其实这个方法虽然有效,但是retry_count
阅读器的代码是不正确的,因为它会依次返回0、0、1、2、3、4、5、6、7 , 8, 9, 10. 双 0 的原因是,在中间件级别,:retry_count
键在第一次执行时不存在,并且在第一次重试时添加键时(也就是第二次执行作业)它的值是0
(不是此代码假定的1
)。
返回nil
, 0, 1, 2, 3, 4, ... 所以if msg['retry_count'].nil? then retry_count = 0 else retry_count = msg['retry_count'] + 1 end
这个答案最初检查了respond_to?(:retry_count)
,但我改为respond_to?(:retry_count=)
,因为这是它实际使用的方法。这可能是@MaxRose-Collins 获得NoMethodError
的部分原因【参考方案2】:
你不需要直接处理这个逻辑来完成你想要的。只需向您的工作人员添加一些配置即可..注意 sidekiq_options
。根据您在下方的评论“阻止 Sidekiq 将作业移至死作业队列”
class MyWorker
include Sidekiq::Worker
sidekiq_options :retry => 5, :dead => false
def perform
#do some stuff
end
end
那么作业应该重试 5 次并优雅地失败。此外,如果您想在重试 5 次后执行代码块,worker 有一个名为 sidekiq_retries_exhausted
的方法,您可以在其中进行一些自定义日志记录等。
【讨论】:
谢谢,但是在 5 次尝试之后,这将作为 失败 工作而结束,我想尝试 5 次,如果它不起作用,请停止而不引发错误。那不一样。sidekiq_retries_exhausted
是同样的事情,已经太晚了,工作失败。我想在它失败之前停止它。
也许我可以使用sidekiq_retries_exhausted
来防止 Sidekiq 将作业移动到死作业队列?
哦,原来这在 Sidekiq 3.0 中真的很简单,答案更新了
太好了,谢谢。下周将升级 Sidekiq 并报告!
文档链接:github.com/mperham/sidekiq/wiki/Error-Handling【参考方案3】:
您可以使用 Sidekiq API 访问重试:
https://github.com/mperham/sidekiq/wiki/API#retries
找到您需要的工作并使用job['retry_count']
获取重试次数。
【讨论】:
谢谢,但可以从 within 作业 while 访问它正在运行的重试。该作业当时不再在 RetrySet 中,因为它是活动的,正在运行的。【参考方案4】:我的用例是避免在部署期间发生异常/停机时安排多个作业。为此,我需要 retry_count。以上解决方案不适用于sidekiq ~> 5.0.4,这是我测试过的解决方案
# config/initializers/sidekiq.rb
# define your middleware
module Sidekiq::Middleware::Server
class SetRetryCountMiddleware
def call(worker, job_params, _queue)
retry_count = job_params["retry_count"]
worker.instance_variable_set(:@retry_count, retry_count)
yield
end
end
end
# add your defined middleware
Sidekiq.configure_server do |config|
config.server_middleware do |chain|
chain.add Sidekiq::Middleware::Server::SetRetryCountMiddleware
end
config.redis = url: "redis://sidekiq:6379/0"
config.logger.level = Logger::INFO
end
& 在你的工人中
class YetAnotherWorker < Base
sidekiq_options :queue => :critical, :retry => true
def perform(args)
begin
# lines that might result in exception
rescue => exception
logger.warn("#exception.class")
raise(exception)
ensure
# below line will ensure job is scheduled only once, avoiding multiple jobs if above lines throws an error
schedule_next_run(my_key: "my_value")
end
end
def schedule_next_run(args)
YetAnotherWorker.perform_at(Time.now + 7.days, args) if first_run
end
def first_run
@retry_count.nil?
end
end
此外,retry_count
密钥在首次运行时在 job_params
中不可用,因此计数看起来像 nil,0,1,2..
【讨论】:
以上是关于工作中的 Sidekiq 重试计数的主要内容,如果未能解决你的问题,请参考以下文章
使用 ActiveJob 禁用自动重试,与 Sidekiq 一起使用
如何使用 ActiveJob 设置 Sidekiq 的重试次数?
部署Cloud66和DigitalOcean的Rails不会影响当前正在运行的sidekiq进程