sidekiq-limit_fetch 0.2 → 0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +13 -2
- data/lib/sidekiq/limit_fetch.rb +16 -7
- data/lib/sidekiq/limit_fetch/queue.rb +8 -8
- data/lib/sidekiq/limit_fetch/semaphore.rb +10 -12
- data/lib/sidekiq/limit_fetch/singleton.rb +11 -0
- data/sidekiq-limit_fetch.gemspec +1 -1
- data/spec/{integration_spec.rb → limit_fetch_spec.rb} +26 -12
- data/spec/sidekiq/limit_fetch/queue_spec.rb +27 -0
- data/spec/spec_helper.rb +7 -0
- metadata +9 -4
data/README.md
CHANGED
@@ -19,9 +19,20 @@ Specify limits which you want to place on queues inside sidekiq.yml:
|
|
19
19
|
queue_name2: 10
|
20
20
|
```
|
21
21
|
|
22
|
-
|
23
|
-
|
22
|
+
Or set it dynamically in your code:
|
23
|
+
```ruby
|
24
|
+
Sidekiq::Queue.new('queue_name1').limit = 5
|
25
|
+
Sidekiq::Queue['queue_name2'].limit = 10
|
26
|
+
```
|
27
|
+
|
28
|
+
In these examples, tasks for the ```queue_name1``` will be run by at most 5
|
29
|
+
workers at the same time and the ```queue_name2``` will have no more than 10
|
24
30
|
workers simultaneously.
|
25
31
|
|
32
|
+
Ability to set limits dynamically allows you to resize worker
|
33
|
+
distribution among queues any time you want.
|
34
|
+
|
35
|
+
Limits are applied strictly for current process.
|
36
|
+
|
26
37
|
Sponsored by [Evil Martians].
|
27
38
|
[Evil Martians]: http://evilmartians.com/
|
data/lib/sidekiq/limit_fetch.rb
CHANGED
@@ -3,11 +3,16 @@ require 'sidekiq/fetch'
|
|
3
3
|
|
4
4
|
class Sidekiq::LimitFetch
|
5
5
|
require_relative 'limit_fetch/semaphore'
|
6
|
-
require_relative 'limit_fetch/queue'
|
7
6
|
require_relative 'limit_fetch/unit_of_work'
|
7
|
+
require_relative 'limit_fetch/singleton'
|
8
|
+
require_relative 'limit_fetch/queue'
|
8
9
|
|
9
10
|
Sidekiq.options[:fetch] = self
|
10
11
|
|
12
|
+
def self.bulk_requeue(jobs)
|
13
|
+
Sidekiq::BasicFetch.bulk_requeue jobs
|
14
|
+
end
|
15
|
+
|
11
16
|
def initialize(options)
|
12
17
|
prepare_queues options
|
13
18
|
options[:strict] ? define_strict_queues : define_weighted_queues
|
@@ -19,14 +24,18 @@ class Sidekiq::LimitFetch
|
|
19
24
|
|
20
25
|
def retrieve_work
|
21
26
|
queues = available_queues
|
27
|
+
|
28
|
+
if queues.empty?
|
29
|
+
sleep Sidekiq::Fetcher::TIMEOUT
|
30
|
+
return
|
31
|
+
end
|
32
|
+
|
22
33
|
queue_name, message = Sidekiq.redis do |it|
|
23
34
|
it.brpop *queues.map(&:full_name), Sidekiq::Fetcher::TIMEOUT
|
24
35
|
end
|
25
36
|
|
26
37
|
if message
|
27
|
-
queue = queues.find {|it| it.full_name == queue_name }
|
28
|
-
queues.delete queue
|
29
|
-
|
38
|
+
queue = queues.delete queues.find {|it| it.full_name == queue_name }
|
30
39
|
UnitOfWork.new queue, message
|
31
40
|
end
|
32
41
|
ensure
|
@@ -36,11 +45,11 @@ class Sidekiq::LimitFetch
|
|
36
45
|
private
|
37
46
|
|
38
47
|
def prepare_queues(options)
|
39
|
-
cache = {}
|
40
48
|
limits = options[:limits] || {}
|
41
|
-
|
42
49
|
@queues = options[:queues].map do |name|
|
43
|
-
|
50
|
+
Sidekiq::Queue.new(name).tap do |it|
|
51
|
+
it.limit = limits[name] if limits[name]
|
52
|
+
end
|
44
53
|
end
|
45
54
|
end
|
46
55
|
|
@@ -1,14 +1,14 @@
|
|
1
|
-
|
1
|
+
module Sidekiq
|
2
2
|
class Queue
|
3
|
-
extend Forwardable
|
3
|
+
extend LimitFetch::Singleton, Forwardable
|
4
|
+
def_delegators :lock, :limit, :limit=, :acquire, :release, :busy
|
4
5
|
|
5
|
-
|
6
|
-
|
6
|
+
def full_name
|
7
|
+
@rname
|
8
|
+
end
|
7
9
|
|
8
|
-
def
|
9
|
-
@
|
10
|
-
@full_name = "queue:#{name}"
|
11
|
-
@lock = Semaphore.for limit
|
10
|
+
def lock
|
11
|
+
@lock ||= LimitFetch::Semaphore.new
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
@@ -1,28 +1,26 @@
|
|
1
1
|
class Sidekiq::LimitFetch::Semaphore
|
2
|
-
|
2
|
+
attr_reader :limit, :busy
|
3
3
|
|
4
|
-
def
|
5
|
-
|
4
|
+
def initialize
|
5
|
+
@lock = Mutex.new
|
6
|
+
@busy = 0
|
6
7
|
end
|
7
8
|
|
8
|
-
def
|
9
|
-
@
|
10
|
-
|
11
|
-
|
12
|
-
def initialize(limit)
|
13
|
-
@lock = Mutex.new
|
14
|
-
@limit = limit
|
9
|
+
def limit=(value)
|
10
|
+
@lock.synchronize do
|
11
|
+
@limit = value
|
12
|
+
end
|
15
13
|
end
|
16
14
|
|
17
15
|
def acquire
|
18
16
|
@lock.synchronize do
|
19
|
-
@
|
17
|
+
@busy += 1 if not @limit or @limit > @busy
|
20
18
|
end
|
21
19
|
end
|
22
20
|
|
23
21
|
def release
|
24
22
|
@lock.synchronize do
|
25
|
-
@
|
23
|
+
@busy -= 1
|
26
24
|
end
|
27
25
|
end
|
28
26
|
end
|
data/sidekiq-limit_fetch.gemspec
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
require '
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Sidekiq::LimitFetch do
|
4
4
|
before :each do
|
5
5
|
Sidekiq.redis do |it|
|
6
|
-
it.del 'queue:
|
7
|
-
it.rpush 'queue:
|
8
|
-
it.expire 'queue:
|
6
|
+
it.del 'queue:example1'
|
7
|
+
it.rpush 'queue:example1', 'task'
|
8
|
+
it.expire 'queue:example1', 30
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
@@ -14,21 +14,21 @@ describe Sidekiq::LimitFetch do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def new_fetcher(options={})
|
17
|
-
described_class.new options.merge queues: %w(
|
17
|
+
described_class.new options.merge queues: %w(example1 example1 example2 example2)
|
18
18
|
end
|
19
19
|
|
20
20
|
it 'should retrieve weighted queues' do
|
21
21
|
fetcher = new_fetcher
|
22
|
-
queues(fetcher).should =~ %w(queue:
|
22
|
+
queues(fetcher).should =~ %w(queue:example1 queue:example2)
|
23
23
|
end
|
24
24
|
|
25
25
|
it 'should retrieve strictly ordered queues' do
|
26
26
|
fetcher = new_fetcher strict: true
|
27
|
-
queues(fetcher).should == %w(queue:
|
27
|
+
queues(fetcher).should == %w(queue:example1 queue:example2)
|
28
28
|
end
|
29
29
|
|
30
|
-
it 'should retrieve
|
31
|
-
fetcher = new_fetcher strict: true, limits: { '
|
30
|
+
it 'should retrieve only available queues' do
|
31
|
+
fetcher = new_fetcher strict: true, limits: { 'example1' => 2 }
|
32
32
|
queues = -> { fetcher.available_queues }
|
33
33
|
|
34
34
|
queues1 = queues.call
|
@@ -47,11 +47,11 @@ describe Sidekiq::LimitFetch do
|
|
47
47
|
end
|
48
48
|
|
49
49
|
it 'should acquire lock on queue for excecution' do
|
50
|
-
fetcher = new_fetcher limits: { '
|
50
|
+
fetcher = new_fetcher limits: { 'example1' => 1, 'example2' => 1 }
|
51
51
|
work = fetcher.retrieve_work
|
52
52
|
work.message.should == 'task'
|
53
|
-
work.queue.should == 'queue:
|
54
|
-
work.queue_name.should == '
|
53
|
+
work.queue.should == 'queue:example1'
|
54
|
+
work.queue_name.should == 'example1'
|
55
55
|
|
56
56
|
queues = fetcher.available_queues
|
57
57
|
queues.should have(1).item
|
@@ -64,4 +64,18 @@ describe Sidekiq::LimitFetch do
|
|
64
64
|
|
65
65
|
fetcher.available_queues.should have(2).items
|
66
66
|
end
|
67
|
+
|
68
|
+
it 'should set queue limits on the fly' do
|
69
|
+
Sidekiq::Queue['example1'].limit = 1
|
70
|
+
Sidekiq::Queue['example2'].limit = 2
|
71
|
+
|
72
|
+
fetcher = new_fetcher
|
73
|
+
|
74
|
+
fetcher.available_queues.should have(2).item
|
75
|
+
fetcher.available_queues.should have(1).item
|
76
|
+
fetcher.available_queues.should have(0).item
|
77
|
+
|
78
|
+
Sidekiq::Queue['example1'].limit = 2
|
79
|
+
fetcher.available_queues.should have(1).item
|
80
|
+
end
|
67
81
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Sidekiq::Queue do
|
4
|
+
context 'singleton' do
|
5
|
+
shared_examples :constructor do
|
6
|
+
it 'with default name' do
|
7
|
+
new_object = -> { described_class.send constructor }
|
8
|
+
new_object.call.should == new_object.call
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'with given name' do
|
12
|
+
new_object = ->(name) { described_class.send constructor, name }
|
13
|
+
new_object.call('name').should == new_object.call('name')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context '.new' do
|
18
|
+
let(:constructor) { :new }
|
19
|
+
it_behaves_like :constructor
|
20
|
+
end
|
21
|
+
|
22
|
+
context '.[]' do
|
23
|
+
let(:constructor) { :[] }
|
24
|
+
it_behaves_like :constructor
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidekiq-limit_fetch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.3'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-01-
|
12
|
+
date: 2013-01-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sidekiq
|
@@ -58,9 +58,12 @@ files:
|
|
58
58
|
- lib/sidekiq/limit_fetch.rb
|
59
59
|
- lib/sidekiq/limit_fetch/queue.rb
|
60
60
|
- lib/sidekiq/limit_fetch/semaphore.rb
|
61
|
+
- lib/sidekiq/limit_fetch/singleton.rb
|
61
62
|
- lib/sidekiq/limit_fetch/unit_of_work.rb
|
62
63
|
- sidekiq-limit_fetch.gemspec
|
63
|
-
- spec/
|
64
|
+
- spec/limit_fetch_spec.rb
|
65
|
+
- spec/sidekiq/limit_fetch/queue_spec.rb
|
66
|
+
- spec/spec_helper.rb
|
64
67
|
homepage: https://github.com/brainopia/sidekiq-limit_fetch
|
65
68
|
licenses: []
|
66
69
|
post_install_message:
|
@@ -86,4 +89,6 @@ signing_key:
|
|
86
89
|
specification_version: 3
|
87
90
|
summary: Sidekig strategy to support queue limits
|
88
91
|
test_files:
|
89
|
-
- spec/
|
92
|
+
- spec/limit_fetch_spec.rb
|
93
|
+
- spec/sidekiq/limit_fetch/queue_spec.rb
|
94
|
+
- spec/spec_helper.rb
|