discourse/lib/sidekiq/pausable.rb

88 lines
1.4 KiB
Ruby

require 'thread'
class SidekiqPauser
def initialize
@mutex = Mutex.new
end
def pause!
@mutex.synchronize do
@paused = true
@pause_thread ||= start_pause_thread
sleep 0.001 while !paused?
end
true
end
def paused?
Sidekiq.redis { |r| !!r.get(paused_key) }
end
def unpause!
@mutex.synchronize do
if @pause_thread
@paused = false
end
@pause_thread.kill
@pause_thread.join
@pause_thread = nil
end
Sidekiq.redis { |r| r.del(paused_key) }
true
end
private
def start_pause_thread
Thread.new do
while @paused do
# TODO retries in case bad redis connectivity
Sidekiq.redis do |r|
r.setex paused_key, 60, "paused"
end
sleep 30
end
end
end
def paused_key
"sidekiq_is_paused_v2"
end
end
module Sidekiq
@pauser = SidekiqPauser.new
def self.pause!
@pauser.pause!
end
def self.paused?
@pauser.paused?
end
def self.unpause!
@pauser.unpause!
end
end
# server middleware that will reschedule work whenever Sidekiq is paused
class Sidekiq::Pausable
attr_reader :delay
def initialize(delay = 5.seconds)
@delay = delay
end
def call(worker, msg, queue)
if Sidekiq.paused?
worker.class.perform_in(delay, *msg['args'])
else
yield
end
end
end