Sidekiq工作人员即使有超时也会运行数千秒

时间:2014-04-03 20:46:35

标签: ruby-on-rails ruby-on-rails-3 redis semaphore sidekiq

我有一个不少于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:检测到死锁。这是否会导致工作人员即使设置超时也永远不会完成?

3 个答案:

答案 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之外。