我有一个不应超过 30 秒的 sidekiq worker,但几天后我会发现整个 worker 队列停止执行,因为所有 worker 都被锁定了。
这是我的 worker :
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-信号量 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 秒,工作人员永远不应该运行。
有人对如何解决这个问题或造成它的原因有任何想法吗? worker 们在 EngineYard 上运行。
编辑:一条附加评论。 #DO WORK 有机会触发 PostgresSQL 函数。我注意到在日志中提到了 PG::TRDeadlockDetected: ERROR: deadlock detected。这会导致工作人员即使设置了超时也永远无法完成吗?
最佳答案
鉴于你想确保唯一的作业执行,我会尝试删除所有锁并将作业唯一性控制委托(delegate)给插件,如 Sidekiq Unique Jobs
在这种情况下,即使 sidetiq 将同一个作业 ID 入队两次,此插件也会确保将其入队/处理一次。
关于ruby-on-rails - 即使超时,Sidekiq worker 仍运行数千秒,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22848655/