У меня есть воркер 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: обнаружена взаимоблокировка. Приведет ли это к тому, что рабочий никогда не завершится даже с установленным тайм-аутом?