mirror of
https://github.com/deanpcmad/sidekiq-limit_fetch.git
synced 2022-11-09 13:54:36 -05:00
Separate probed and busy indicators for queue
This commit is contained in:
parent
afb7763561
commit
f1e83a3384
12 changed files with 87 additions and 57 deletions
|
@ -3,20 +3,17 @@ module Sidekiq
|
|||
extend LimitFetch::Singleton, Forwardable
|
||||
|
||||
def_delegators :lock,
|
||||
:limit, :limit=,
|
||||
:acquire, :release,
|
||||
:pause, :unpause,
|
||||
:block, :unblock,
|
||||
:paused?, :blocking?,
|
||||
:unblocked, :block_except,
|
||||
:busy
|
||||
:limit, :limit=,
|
||||
:acquire, :release,
|
||||
:pause, :unpause,
|
||||
:block, :unblock,
|
||||
:paused?, :blocking?,
|
||||
:unblocked, :block_except,
|
||||
:probed, :busy,
|
||||
:increase_busy, :decrease_busy
|
||||
|
||||
def lock
|
||||
@lock ||= mode::Semaphore.new name
|
||||
end
|
||||
|
||||
def mode
|
||||
Sidekiq.options[:local] ? LimitFetch::Local : LimitFetch::Global
|
||||
@lock ||= LimitFetch::Global::Semaphore.new name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -37,8 +37,10 @@ module Sidekiq::LimitFetch::Global
|
|||
next if it.get heartbeat_key processor
|
||||
|
||||
it.del processor_key processor
|
||||
it.keys('limit_fetch:busy:*').each do |queue|
|
||||
it.lrem queue, 0, processor
|
||||
%w(limit_fetch:probed:* limit_fetch:busy:*).each do |pattern|
|
||||
it.keys(pattern).each do |queue|
|
||||
it.lrem queue, 0, processor
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -60,7 +60,7 @@ module Sidekiq::LimitFetch::Global
|
|||
|
||||
for _, queue in ipairs(queues) do
|
||||
if not blocking_mode or unblocked[queue] then
|
||||
local busy_key = namespace..'busy:'..queue
|
||||
local probed_key = namespace..'probed:'..queue
|
||||
local pause_key = namespace..'pause:'..queue
|
||||
local paused = redis.call('get', pause_key)
|
||||
|
||||
|
@ -72,7 +72,7 @@ module Sidekiq::LimitFetch::Global
|
|||
local can_block = redis.call('get', block_key)
|
||||
|
||||
if can_block or queue_limit then
|
||||
queue_locks = redis.call('llen', busy_key)
|
||||
queue_locks = redis.call('llen', probed_key)
|
||||
end
|
||||
|
||||
blocking_mode = can_block and queue_locks > 0
|
||||
|
@ -84,7 +84,7 @@ module Sidekiq::LimitFetch::Global
|
|||
end
|
||||
|
||||
if not queue_limit or queue_limit > queue_locks then
|
||||
redis.call('rpush', busy_key, worker_name)
|
||||
redis.call('rpush', probed_key, worker_name)
|
||||
table.insert(available, queue)
|
||||
end
|
||||
end
|
||||
|
@ -102,8 +102,8 @@ module Sidekiq::LimitFetch::Global
|
|||
local queues = ARGV
|
||||
|
||||
for _, queue in ipairs(queues) do
|
||||
local busy_key = namespace..'busy:'..queue
|
||||
redis.call('lrem', busy_key, 1, worker_name)
|
||||
local probed_key = namespace..'probed:'..queue
|
||||
redis.call('lrem', probed_key, 1, worker_name)
|
||||
end
|
||||
LUA
|
||||
end
|
||||
|
|
|
@ -23,13 +23,25 @@ module Sidekiq::LimitFetch::Global
|
|||
end
|
||||
|
||||
def release
|
||||
Selector.release [@name]
|
||||
redis {|it| it.lrem "#{PREFIX}:probed:#@name", 1, Selector.uuid }
|
||||
end
|
||||
|
||||
def busy
|
||||
redis {|it| it.llen "#{PREFIX}:busy:#@name" }
|
||||
end
|
||||
|
||||
def increase_busy
|
||||
redis {|it| it.rpush "#{PREFIX}:busy:#@name", Selector.uuid }
|
||||
end
|
||||
|
||||
def decrease_busy
|
||||
redis {|it| it.lrem "#{PREFIX}:busy:#@name", 1, Selector.uuid }
|
||||
end
|
||||
|
||||
def probed
|
||||
redis {|it| it.llen "#{PREFIX}:probed:#@name" }
|
||||
end
|
||||
|
||||
def pause
|
||||
redis {|it| it.set "#{PREFIX}:pause:#@name", true }
|
||||
end
|
||||
|
|
|
@ -1,19 +1,17 @@
|
|||
class Sidekiq::LimitFetch
|
||||
class Queues
|
||||
THREAD_KEY = :acquired_queues
|
||||
attr_reader :selector
|
||||
|
||||
def initialize(options)
|
||||
@queues = options[:queues]
|
||||
options[:strict] ? strict_order! : weighted_order!
|
||||
|
||||
set_selector options[:local]
|
||||
set_limits options[:limits]
|
||||
set_blocks options[:blocking]
|
||||
end
|
||||
|
||||
def acquire
|
||||
@selector.acquire(ordered_queues)
|
||||
selector.acquire(ordered_queues)
|
||||
.tap {|it| save it }
|
||||
.map {|it| "queue:#{it}" }
|
||||
end
|
||||
|
@ -21,13 +19,13 @@ class Sidekiq::LimitFetch
|
|||
def release_except(full_name)
|
||||
queues = restore
|
||||
queues.delete full_name[/queue:(.*)/, 1] if full_name
|
||||
@selector.release queues
|
||||
selector.release queues
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_selector(local)
|
||||
@selector = local ? Local::Selector : Global::Selector
|
||||
def selector
|
||||
Global::Selector
|
||||
end
|
||||
|
||||
def set_limits(limits)
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
module Sidekiq
|
||||
class LimitFetch::UnitOfWork < BasicFetch::UnitOfWork
|
||||
def initialize(queue, message)
|
||||
super
|
||||
Queue[queue_name].increase_busy
|
||||
end
|
||||
|
||||
def acknowledge
|
||||
Queue[queue_name].decrease_busy
|
||||
Queue[queue_name].release
|
||||
end
|
||||
|
||||
|
|
|
@ -59,14 +59,14 @@ describe Sidekiq::Queue do
|
|||
it 'should be countable' do
|
||||
queue.limit = 3
|
||||
5.times { queue.acquire }
|
||||
queue.busy.should == 3
|
||||
queue.probed.should == 3
|
||||
end
|
||||
|
||||
it 'should be releasable' do
|
||||
queue.acquire
|
||||
queue.busy.should == 1
|
||||
queue.probed.should == 1
|
||||
queue.release
|
||||
queue.busy.should == 0
|
||||
queue.probed.should == 0
|
||||
end
|
||||
|
||||
it 'should tell if paused' do
|
||||
|
|
|
@ -20,11 +20,11 @@ describe Sidekiq::LimitFetch::Global::Monitor do
|
|||
it 'should remove invalidated old locks' do
|
||||
2.times { queue.acquire }
|
||||
sleep 2*ttl
|
||||
queue.busy.should == 2
|
||||
queue.probed.should == 2
|
||||
|
||||
described_class.stub :update_heartbeat
|
||||
sleep 2*ttl
|
||||
queue.busy.should == 0
|
||||
queue.probed.should == 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,46 +17,46 @@ describe Sidekiq::LimitFetch::Queues do
|
|||
|
||||
it 'should acquire queues' do
|
||||
subject.acquire
|
||||
Sidekiq::Queue['queue1'].busy.should == 1
|
||||
Sidekiq::Queue['queue2'].busy.should == 1
|
||||
Sidekiq::Queue['queue1'].probed.should == 1
|
||||
Sidekiq::Queue['queue2'].probed.should == 1
|
||||
end
|
||||
|
||||
it 'should acquire dynamically blocking queues' do
|
||||
subject.acquire
|
||||
Sidekiq::Queue['queue1'].busy.should == 1
|
||||
Sidekiq::Queue['queue2'].busy.should == 1
|
||||
Sidekiq::Queue['queue1'].probed.should == 1
|
||||
Sidekiq::Queue['queue2'].probed.should == 1
|
||||
|
||||
Sidekiq::Queue['queue1'].block
|
||||
|
||||
subject.acquire
|
||||
Sidekiq::Queue['queue1'].busy.should == 2
|
||||
Sidekiq::Queue['queue2'].busy.should == 1
|
||||
Sidekiq::Queue['queue1'].probed.should == 2
|
||||
Sidekiq::Queue['queue2'].probed.should == 1
|
||||
end
|
||||
|
||||
it 'should block except given queues' do
|
||||
Sidekiq::Queue['queue1'].block_except 'queue2'
|
||||
subject.acquire
|
||||
Sidekiq::Queue['queue1'].busy.should == 1
|
||||
Sidekiq::Queue['queue2'].busy.should == 1
|
||||
Sidekiq::Queue['queue1'].probed.should == 1
|
||||
Sidekiq::Queue['queue2'].probed.should == 1
|
||||
|
||||
Sidekiq::Queue['queue1'].block_except 'queue404'
|
||||
subject.acquire
|
||||
Sidekiq::Queue['queue1'].busy.should == 2
|
||||
Sidekiq::Queue['queue2'].busy.should == 1
|
||||
Sidekiq::Queue['queue1'].probed.should == 2
|
||||
Sidekiq::Queue['queue2'].probed.should == 1
|
||||
end
|
||||
|
||||
it 'should release queues' do
|
||||
subject.acquire
|
||||
subject.release_except nil
|
||||
Sidekiq::Queue['queue1'].busy.should == 0
|
||||
Sidekiq::Queue['queue2'].busy.should == 0
|
||||
Sidekiq::Queue['queue1'].probed.should == 0
|
||||
Sidekiq::Queue['queue2'].probed.should == 0
|
||||
end
|
||||
|
||||
it 'should release queues except selected' do
|
||||
subject.acquire
|
||||
subject.release_except 'queue:queue1'
|
||||
Sidekiq::Queue['queue1'].busy.should == 1
|
||||
Sidekiq::Queue['queue2'].busy.should == 0
|
||||
Sidekiq::Queue['queue1'].probed.should == 1
|
||||
Sidekiq::Queue['queue2'].probed.should == 0
|
||||
end
|
||||
|
||||
it 'should release when no queues was acquired' do
|
||||
|
@ -70,8 +70,8 @@ describe Sidekiq::LimitFetch::Queues do
|
|||
|
||||
it 'should acquire blocking queues' do
|
||||
3.times { subject.acquire }
|
||||
Sidekiq::Queue['queue1'].busy.should == 3
|
||||
Sidekiq::Queue['queue2'].busy.should == 1
|
||||
Sidekiq::Queue['queue1'].probed.should == 3
|
||||
Sidekiq::Queue['queue2'].probed.should == 1
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -15,28 +15,28 @@ describe 'semaphore' do
|
|||
|
||||
it 'should acquire and count active tasks' do
|
||||
3.times { subject.acquire }
|
||||
subject.busy.should == 3
|
||||
subject.probed.should == 3
|
||||
end
|
||||
|
||||
it 'should acquire tasks with regard to limit' do
|
||||
subject.limit = 4
|
||||
6.times { subject.acquire }
|
||||
subject.busy.should == 4
|
||||
subject.probed.should == 4
|
||||
end
|
||||
|
||||
it 'should release active tasks' do
|
||||
6.times { subject.acquire }
|
||||
3.times { subject.release }
|
||||
subject.busy.should == 3
|
||||
subject.probed.should == 3
|
||||
end
|
||||
|
||||
it 'should pause tasks' do
|
||||
3.times { subject.acquire }
|
||||
subject.pause
|
||||
2.times { subject.acquire }
|
||||
subject.busy.should == 3
|
||||
subject.probed.should == 3
|
||||
2.times { subject.release }
|
||||
subject.busy.should == 1
|
||||
subject.probed.should == 1
|
||||
end
|
||||
|
||||
it 'should unpause tasks' do
|
||||
|
@ -44,6 +44,6 @@ describe 'semaphore' do
|
|||
3.times { subject.acquire }
|
||||
subject.unpause
|
||||
2.times { subject.acquire }
|
||||
subject.busy.should == 2
|
||||
subject.probed.should == 2
|
||||
end
|
||||
end
|
||||
|
|
|
@ -20,15 +20,27 @@ describe Sidekiq::LimitFetch do
|
|||
work.queue_name.should == 'queue1'
|
||||
work.message.should == 'task1'
|
||||
|
||||
Sidekiq::Queue['queue1'].busy.should == 1
|
||||
Sidekiq::Queue['queue2'].busy.should == 0
|
||||
|
||||
subject.retrieve_work.should_not be
|
||||
work.requeue
|
||||
|
||||
Sidekiq::Queue['queue1'].busy.should == 0
|
||||
Sidekiq::Queue['queue2'].busy.should == 0
|
||||
|
||||
work = subject.retrieve_work
|
||||
work.message.should == 'task2'
|
||||
|
||||
Sidekiq::Queue['queue1'].busy.should == 1
|
||||
Sidekiq::Queue['queue2'].busy.should == 0
|
||||
|
||||
subject.retrieve_work.should_not be
|
||||
work.acknowledge
|
||||
|
||||
Sidekiq::Queue['queue1'].busy.should == 0
|
||||
Sidekiq::Queue['queue2'].busy.should == 0
|
||||
|
||||
work = subject.retrieve_work
|
||||
work.message.should == 'task1'
|
||||
end
|
||||
|
|
|
@ -6,10 +6,13 @@ RSpec.configure do |config|
|
|||
config.before :each do
|
||||
Sidekiq.redis do |it|
|
||||
clean_redis = ->(queue) do
|
||||
it.del "limit_fetch:limit:#{queue}"
|
||||
it.del "limit_fetch:busy:#{queue}"
|
||||
it.del "limit_fetch:pause:#{queue}"
|
||||
it.del "limit_fetch:block:#{queue}"
|
||||
it.pipelined do
|
||||
it.del "limit_fetch:limit:#{queue}"
|
||||
it.del "limit_fetch:busy:#{queue}"
|
||||
it.del "limit_fetch:probed:#{queue}"
|
||||
it.del "limit_fetch:pause:#{queue}"
|
||||
it.del "limit_fetch:block:#{queue}"
|
||||
end
|
||||
end
|
||||
|
||||
clean_redis.call(name) if defined?(name)
|
||||
|
|
Loading…
Reference in a new issue