我有一个不少于30秒的sidekiq工作者,但几天后我会发现整个工作队列都停止执行,因为所有工作人员都被锁定了。
这是我的工作人员:
class MyWorker
include Sidekiq::Worker
include Sidekiq::Status::Worker
sidekiq_options queue: :my_queue, retry: 5, timeout: 4.minutes
sidekiq_retry_in do |count|
5
end
sidekiq_retries_exhausted do |msg|
store({message: "Gave up."})
end
def perform(id)
begin
Timeout::timeout(3.minutes) do
got_lock = with_semaphore("lock_#{id}") do
# DO WORK
end
end
rescue ActiveRecord::RecordNotFound => e
# Handle
rescue Timeout::Error => e
# Handle
raise e
end
end
def with_semaphore(name, &block)
Semaphore.get(name, {stale_client_timeout: 1.minute}).lock(1, &block)
end
end
我们使用的信号量类。 (redis-semaphore gem)
class Semaphore
def self.get(name, options = {})
Redis::Semaphore.new(name.to_sym,
:redis => Application.redis,
stale_client_timeout: options[:stale_client_timeout] || 1.hour,
)
end
end
基本上我会停止工人并且它将完成状态:10000秒,工人永远不应该为此工作。
任何人对如何解决这个或导致它的原因有任何想法?工人们在EngineYard上运行。
编辑:另外一条评论。 #DO WORK有机会启动PostgresSQL功能。我在日志中注意到一些提到PG :: TRDeadlockDetected:ERROR:检测到死锁。这是否会导致工作人员即使设置超时也永远不会完成?
答案 0 :(得分:1)
鉴于您希望确保唯一的作业执行,我会尝试删除所有锁并将作业唯一性控制委托给Sidekiq Unique Jobs等插件
在这种情况下,即使sidetiq将相同的作业ID排队两次,此插件也会确保它将被排队/处理一次。
答案 1 :(得分:0)
您也可以尝试使用ActiveRecord with_lock
机制:http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html
答案 2 :(得分:0)
我以前也有类似的问题。要解决此问题,您应该停止使用超时。
如this article中所述,切勿在Sidekiq作业中使用超时。如果使用超时,则Sidekiq进程和线程很容易中断。
不仅Ruby,Java也有a similar problem。无论使用哪种语言,从外部停止线程本质上都是危险的。
如果删除“超时”后仍然出现相同的问题,请检查代码中是否在不慎使用线程。
由于Sidekiq的体系结构非常复杂,因此几乎在所有情况下,该错误的来源都在Sidekiq之外。