Рабочий процесс Sidekiq работает тысячи секунд, несмотря на тайм-аут

У меня есть воркер sidekiq, который не должен занимать более 30 секунд, но через несколько дней я обнаружу, что вся очередь воркеров перестает выполняться, потому что все воркеры заблокированы.

Вот мой рабочий:

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)

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 секунд», в течение которых рабочий НИКОГДА не должен работать.

У кого-нибудь есть идеи, как это исправить или в чем причина? Рабочие бегут по машинному двору.

Изменить: один дополнительный комментарий. # DO WORK может запустить функцию PostgresSQL. Я заметил в логах упоминания о PG::TRDeadlockDetected: ERROR: обнаружена взаимоблокировка. Приведет ли это к тому, что рабочий никогда не завершится даже с установленным тайм-аутом?


person Geesu    schedule 03.04.2014    source источник
comment
Есть ли какая-то конкретная причина, по которой вы используете блокировку семафора внутри рабочего метода выполнения? Я спрашиваю об этом, потому что считаю эту смесь Sidekiq+Locking немного опасной. Сотрудники Sidekiq рекомендуют максимально изолировать рабочие места, чтобы не было узких мест. или потенциальные взаимоблокировки, которые могут возникнуть при блокировке вещей во время #perform   -  person Gustavo Barrancos    schedule 04.04.2014
comment
В сочетании с sidetiq я замечаю, что иногда один и тот же идентификатор будет выброшен в очередь для обработки, что предотвращает его повторную обработку.   -  person Geesu    schedule 04.04.2014


Ответы (3)


Учитывая, что вы хотите обеспечить уникальное выполнение задания, я бы попытался удалить все блокировки и делегировать управление уникальностью задания плагину, например Уникальные вакансии Sidekiq

В этом случае, даже если sidetiq дважды поставит в очередь один и тот же идентификатор задания, этот плагин гарантирует, что оно будет поставлено в очередь/обработано один раз.

person Gustavo Barrancos    schedule 04.04.2014
comment
Итак, вы считаете, что проблема в redis-семафоре? Я до сих пор не понимаю, почему тайм-аут игнорируется. - person Geesu; 04.04.2014

Вы также можете попробовать механизм ActiveRecord with_lock: http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html

person lobati    schedule 28.05.2014
comment
Я действительно подозреваю, что это может быть реальной причиной проблемы: blog.headius.com/2008/02/ - person Geesu; 31.05.2014
comment
Ага, очень похоже. Примечание для себя, не превышайте тайм-аут с блокировкой базы данных. Есть ли причина, по которой вам нужно время ожидания? Может быть, есть способ разбить логику, чтобы разрешить доступ к промежуточной записи. - person lobati; 31.05.2014
comment
Кстати, вы должны подумать над тем, чтобы ответить на свой вопрос. - person lobati; 31.05.2014

У меня была похожая проблема раньше. Чтобы решить эту проблему, вы должны прекратить использовать Timeout.

Как объясняется в этой статье, никогда не следует использовать Timeout в Sidekiq. работа. Если вы используете Timeout, процессы и потоки Sidekiq могут легко сломаться.

Не только в Ruby, но и в Java есть похожая проблема< /а>. Остановка потока извне по своей сути опасна, независимо от языка.

Если у вас по-прежнему возникает та же проблема после удаления Timeout, проверьте, не используете ли вы потоки в своем коде небрежно.

Поскольку архитектура Sidekiq настолько сложна, почти во всех случаях источник ошибки находится за пределами Sidekiq.

person Teruki Shinohara    schedule 02.05.2020