sidekiq-limit_fetch 2.4.2 → 3.0.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1edc411f8e5b3ab852b0b005548a28fafd0167e4
4
- data.tar.gz: df6b938724aa978eab9757d1c969c9577c9e58c3
3
+ metadata.gz: 76501c38471c02fe380102202fbd2afb9799976e
4
+ data.tar.gz: 20d1ed4d5d36ca62b7dcff40e09842378ba1d3a1
5
5
  SHA512:
6
- metadata.gz: 4cb020c997e1dc814969e949ae497f49ee048f4d8b0b18833dd8eca51de0a1b943cae09d2e34e523e9d9c29b251101bf707cbab67d7a5ff270cda43be69ffbbd
7
- data.tar.gz: 29eb71b1e70bde0da6dee13798e2fae39c2900abca6cbcf25d22ab2466028525ef84ff4abb3c00b02b48524b4ffef09bb8a98f432761d9e5081bf3a656c7d24e
6
+ metadata.gz: b14c94fad7ef434afc4b16e58f3517a426bf1f95f31aac2b12b279e4f72e70ebb11746b58ca1873d582a32568c5d27cc6fe05daf28f5a3e0f299361f7ebdc015
7
+ data.tar.gz: 030fe7be744ff109d6ff17740e71576f9011f432255ce00ab5423dcd5486e75d2a76cf9e0c06825f5fbc962aab6fbe6a4d3a4e46931698006e3e9e39467ae3c7
data/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  Gemfile.lock
2
2
  pkg/
3
+ .bundle/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper --color
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
1
  source 'https://rubygems.org'
2
2
  gemspec
3
3
 
4
- gem 'sidekiq', github: 'mperham/sidekiq'
4
+ gem 'sidekiq', github: 'mperham/sidekiq', branch: 'internal_rewrite'
data/README.md CHANGED
@@ -18,7 +18,10 @@ Add this line to your application's Gemfile:
18
18
 
19
19
  redis 2.6 or newer
20
20
 
21
- **Important note:** At this moment, `sidekiq-limit_fetch` is incompatible with Sidekiq Pro's `reliable_fetch`.
21
+ **Important note:** At this moment, `sidekiq-limit_fetch` is incompatible with
22
+ - sidekiq pro's `reliable_fetch`
23
+ - `sidekiq-rate-limiter`
24
+ - any other plugin that rewrites fetch strategy of sidekiq.
22
25
 
23
26
  https://github.com/mperham/sidekiq/issues/1508 — a sidekiq admin busy page is unreliable, so if you need to check how many workers are running a queue use a `#busy` method described below.
24
27
 
@@ -146,6 +149,9 @@ To use this mode you need to specify a following line in sidekiq.yml:
146
149
 
147
150
  Dynamic queues will be ran at the lowest priority.
148
151
 
152
+ ### Maintenance
153
+
154
+ If you use ```flushdb```, restart the sidekiq process to re-populate the dynamic configuration.
149
155
 
150
156
  ### Thanks
151
157
 
@@ -0,0 +1,16 @@
1
+ class Sidekiq::Manager
2
+ module InitLimitFetch
3
+ def initialize(options={})
4
+ options[:fetch] = Sidekiq::LimitFetch
5
+ super
6
+ end
7
+
8
+ def start
9
+ Sidekiq::LimitFetch::Queues.start options
10
+ Global::Monitor.start!
11
+ super
12
+ end
13
+ end
14
+
15
+ prepend InitLimitFetch
16
+ end
@@ -1,6 +1,6 @@
1
1
  module Sidekiq
2
2
  class Queue
3
- extend LimitFetch::Singleton, Forwardable
3
+ extend LimitFetch::Instances, Forwardable
4
4
  attr_reader :rname
5
5
 
6
6
  def_delegators :lock,
@@ -1,6 +1,5 @@
1
1
  module Sidekiq::LimitFetch::Global
2
2
  module Monitor
3
- include Sidekiq::LimitFetch::Redis
4
3
  extend self
5
4
 
6
5
  HEARTBEAT_PREFIX = 'limit:heartbeat:'
@@ -8,10 +7,10 @@ module Sidekiq::LimitFetch::Global
8
7
  HEARTBEAT_TTL = 20
9
8
  REFRESH_TIMEOUT = 5
10
9
 
11
- def start!(queues, ttl=HEARTBEAT_TTL, timeout=REFRESH_TIMEOUT)
10
+ def start!(ttl=HEARTBEAT_TTL, timeout=REFRESH_TIMEOUT)
12
11
  Thread.new do
13
12
  loop do
14
- add_dynamic queues if queues.dynamic?
13
+ add_dynamic_queues
15
14
  update_heartbeat ttl
16
15
  invalidate_old_processes
17
16
  sleep timeout
@@ -20,23 +19,24 @@ module Sidekiq::LimitFetch::Global
20
19
  end
21
20
 
22
21
  def all_processes
23
- redis {|it| it.smembers PROCESS_SET }
22
+ Sidekiq.redis {|it| it.smembers PROCESS_SET }
24
23
  end
25
24
 
26
25
  def old_processes
27
26
  all_processes.reject do |process|
28
- redis {|it| it.get heartbeat_key process }
27
+ Sidekiq.redis {|it| it.get heartbeat_key process }
29
28
  end
30
29
  end
31
30
 
32
31
  def remove_old_processes!
33
- redis do |it|
32
+ Sidekiq.redis do |it|
34
33
  old_processes.each {|process| it.srem PROCESS_SET, process }
35
34
  end
36
35
  end
37
36
 
38
- def add_dynamic(queues)
39
- queues.add Sidekiq::Queue.all.map(&:name)
37
+ def add_dynamic_queues
38
+ queues = Sidekiq::LimitFetch::Queues
39
+ queues.add Sidekiq::Queue.all.map(&:name) if queues.dynamic?
40
40
  end
41
41
 
42
42
  private
@@ -1,7 +1,5 @@
1
1
  module Sidekiq::LimitFetch::Global
2
2
  class Semaphore
3
- include Sidekiq::LimitFetch::Redis
4
-
5
3
  PREFIX = 'limit_fetch'
6
4
 
7
5
  attr_reader :local_busy
@@ -45,7 +43,7 @@ module Sidekiq::LimitFetch::Global
45
43
  end
46
44
 
47
45
  def acquire
48
- Selector.acquire([@name], determine_namespace).size > 0
46
+ Selector.acquire([@name], namespace).size > 0
49
47
  end
50
48
 
51
49
  def release
@@ -163,5 +161,15 @@ module Sidekiq::LimitFetch::Global
163
161
  it.lrem "#{PREFIX}:busy:#@name", 0, process
164
162
  end
165
163
  end
164
+
165
+ private
166
+
167
+ def redis(&block)
168
+ Sidekiq.redis(&block)
169
+ end
170
+
171
+ def namespace
172
+ Sidekiq::LimitFetch::Queues.namespace
173
+ end
166
174
  end
167
175
  end
@@ -1,4 +1,4 @@
1
- module Sidekiq::LimitFetch::Singleton
1
+ module Sidekiq::LimitFetch::Instances
2
2
  def self.extended(klass)
3
3
  klass.instance_variable_set :@instances, {}
4
4
  end
@@ -1,88 +1,97 @@
1
- class Sidekiq::LimitFetch
2
- class Queues
3
- THREAD_KEY = :acquired_queues
1
+ module Sidekiq::LimitFetch::Queues
2
+ extend self
4
3
 
5
- def initialize(options)
6
- @queues = options[:queues]
7
- @namespace = options[:namespace]
8
- @dynamic = options[:dynamic]
4
+ THREAD_KEY = :acquired_queues
9
5
 
10
- options[:strict] ? strict_order! : weighted_order!
6
+ def start(options)
7
+ @queues = options[:queues]
8
+ @dynamic = options[:dynamic]
11
9
 
12
- set :process_limit, options[:process_limits]
13
- set :limit, options[:limits]
14
- set_blocks options[:blocking]
15
- end
10
+ options[:strict] ? strict_order! : weighted_order!
16
11
 
17
- def acquire
18
- selector.acquire(ordered_queues, @namespace)
19
- .tap {|it| save it }
20
- .map {|it| "queue:#{it}" }
21
- end
12
+ set :process_limit, options[:process_limits]
13
+ set :limit, options[:limits]
14
+ set_blocks options[:blocking]
15
+ end
22
16
 
23
- def release_except(full_name)
24
- queues = restore
25
- queues.delete full_name[/queue:(.*)/, 1] if full_name
26
- selector.release queues, @namespace
27
- end
17
+ def acquire
18
+ selector.acquire(ordered_queues, namespace)
19
+ .tap {|it| save it }
20
+ .map {|it| "queue:#{it}" }
21
+ end
28
22
 
29
- def dynamic?
30
- @dynamic
31
- end
23
+ def release_except(full_name)
24
+ queues = restore
25
+ queues.delete full_name[/queue:(.*)/, 1] if full_name
26
+ selector.release queues, namespace
27
+ end
32
28
 
33
- def add(queues)
34
- queues.each do |queue|
35
- @queues.push queue unless @queues.include? queue
36
- end
37
- end
29
+ def dynamic?
30
+ @dynamic
31
+ end
38
32
 
39
- def strict_order!
40
- @queues.uniq!
41
- def ordered_queues; @queues end
33
+ def add(queues)
34
+ queues.each do |queue|
35
+ @queues.push queue unless @queues.include? queue
42
36
  end
37
+ end
43
38
 
44
- def weighted_order!
45
- def ordered_queues; @queues.shuffle.uniq end
46
- end
39
+ def strict_order!
40
+ @queues.uniq!
41
+ def ordered_queues; @queues end
42
+ end
47
43
 
48
- private
44
+ def weighted_order!
45
+ def ordered_queues; @queues.shuffle.uniq end
46
+ end
49
47
 
50
- def selector
51
- Global::Selector
48
+ def namespace
49
+ @namespace ||= Sidekiq.redis do |it|
50
+ if it.respond_to?(:namespace) and it.namespace
51
+ it.namespace + ':'
52
+ else
53
+ ''
54
+ end
52
55
  end
56
+ end
53
57
 
54
- def set(limit_type, limits)
55
- limits ||= {}
56
- each_queue do |queue|
57
- limit = limits[queue.name.to_s] || limits[queue.name.to_sym]
58
- queue.send "#{limit_type}=", limit unless queue.limit_changed?
59
- end
58
+ private
59
+
60
+ def selector
61
+ Sidekiq::LimitFetch::Global::Selector
62
+ end
63
+
64
+ def set(limit_type, limits)
65
+ limits ||= {}
66
+ each_queue do |queue|
67
+ limit = limits[queue.name.to_s] || limits[queue.name.to_sym]
68
+ queue.send "#{limit_type}=", limit unless queue.limit_changed?
60
69
  end
70
+ end
61
71
 
62
- def set_blocks(blocks)
63
- each_queue(&:unblock)
72
+ def set_blocks(blocks)
73
+ each_queue(&:unblock)
64
74
 
65
- blocks.to_a.each do |it|
66
- if it.is_a? Array
67
- it.each {|name| Sidekiq::Queue[name].block_except it }
68
- else
69
- Sidekiq::Queue[it].block
70
- end
75
+ blocks.to_a.each do |it|
76
+ if it.is_a? Array
77
+ it.each {|name| Sidekiq::Queue[name].block_except it }
78
+ else
79
+ Sidekiq::Queue[it].block
71
80
  end
72
81
  end
82
+ end
73
83
 
74
- def save(queues)
75
- Thread.current[THREAD_KEY] = queues
76
- end
84
+ def save(queues)
85
+ Thread.current[THREAD_KEY] = queues
86
+ end
77
87
 
78
- def restore
79
- Thread.current[THREAD_KEY] || []
80
- ensure
81
- Thread.current[THREAD_KEY] = nil
82
- end
88
+ def restore
89
+ Thread.current[THREAD_KEY] || []
90
+ ensure
91
+ Thread.current[THREAD_KEY] = nil
92
+ end
83
93
 
84
- def each_queue
85
- @queues.uniq.each {|it| yield Sidekiq::Queue[it] }
86
- end
94
+ def each_queue
95
+ @queues.uniq.each {|it| yield Sidekiq::Queue[it] }
87
96
  end
88
97
  end
@@ -1,56 +1,39 @@
1
+ require 'forwardable'
1
2
  require 'sidekiq'
2
- require 'sidekiq/util'
3
+ require 'sidekiq/manager'
3
4
  require 'sidekiq/api'
4
- require 'forwardable'
5
5
 
6
- class Sidekiq::LimitFetch
6
+ module Sidekiq::LimitFetch
7
7
  autoload :UnitOfWork, 'sidekiq/limit_fetch/unit_of_work'
8
8
 
9
- require_relative 'limit_fetch/redis'
10
- require_relative 'limit_fetch/singleton'
9
+ require_relative 'limit_fetch/instances'
11
10
  require_relative 'limit_fetch/queues'
12
11
  require_relative 'limit_fetch/global/semaphore'
13
12
  require_relative 'limit_fetch/global/selector'
14
13
  require_relative 'limit_fetch/global/monitor'
15
14
  require_relative 'extensions/queue'
15
+ require_relative 'extensions/manager'
16
16
 
17
- include Redis
18
- Sidekiq.options[:fetch] = self
19
-
20
- def self.bulk_requeue(*args)
21
- Sidekiq::BasicFetch.bulk_requeue *args
22
- end
17
+ extend self
23
18
 
24
- def initialize(options)
25
- @queues = Queues.new options.merge(namespace: determine_namespace)
26
- Global::Monitor.start! @queues
19
+ def new(_)
20
+ self
27
21
  end
28
22
 
29
23
  def retrieve_work
30
- queue, message = fetch_message
24
+ queue, message = redis_brpop *Queues.acquire, Sidekiq::BasicFetch::TIMEOUT
25
+ Queues.release_except queue
31
26
  UnitOfWork.new queue, message if message
32
27
  end
33
28
 
34
- private
35
-
36
- def fetch_message
37
- queue, _ = redis_brpop *@queues.acquire, Sidekiq::Fetcher::TIMEOUT
38
- ensure
39
- @queues.release_except queue
29
+ def bulk_requeue(*args)
30
+ Sidekiq::BasicFetch.bulk_requeue(*args)
40
31
  end
41
32
 
33
+ private
34
+
42
35
  def redis_brpop(*args)
43
36
  return if args.size < 2
44
- query = -> redis { redis.brpop *args }
45
-
46
- if busy_local_queues.any? {|queue| not args.include? queue.rname }
47
- nonblocking_redis(&query)
48
- else
49
- redis(&query)
50
- end
51
- end
52
-
53
- def busy_local_queues
54
- Sidekiq::Queue.instances.select(&:local_busy?)
37
+ Sidekiq.redis {|it| it.brpop *args }
55
38
  end
56
39
  end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |gem|
2
2
  gem.name = 'sidekiq-limit_fetch'
3
- gem.version = '2.4.2'
3
+ gem.version = '3.0.0'
4
4
  gem.license = 'MIT'
5
5
  gem.authors = 'brainopia'
6
6
  gem.email = 'brainopia@evilmartians.com'
@@ -13,9 +13,9 @@ Gem::Specification.new do |gem|
13
13
 
14
14
  gem.files = `git ls-files`.split($/)
15
15
  gem.test_files = gem.files.grep %r{^spec/}
16
- gem.require_paths = %w(lib)
16
+ gem.require_paths = 'lib'
17
17
 
18
- gem.add_dependency 'sidekiq', '>= 2.6.5', '< 4.0'
19
- gem.add_development_dependency 'rspec', '~> 3.2.0'
18
+ gem.add_dependency 'sidekiq', '>= 4'
19
+ gem.add_development_dependency 'rspec'
20
20
  gem.add_development_dependency 'rake'
21
21
  end
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
1
  RSpec.describe Sidekiq::Queue do
4
2
  context 'singleton' do
5
3
  shared_examples :constructor do
@@ -1,21 +1,11 @@
1
- require 'spec_helper'
2
-
3
- Thread.abort_on_exception = true
4
-
5
1
  RSpec.describe Sidekiq::LimitFetch::Global::Monitor do
6
- let(:queues) { double dynamic?: false }
7
- let(:monitor) { described_class.start! queues, ttl, timeout }
2
+ let(:monitor) { described_class.start! ttl, timeout }
8
3
  let(:ttl) { 1 }
9
4
  let(:queue) { Sidekiq::Queue[name] }
10
5
  let(:name) { 'default' }
11
6
 
12
- before :each do
13
- monitor
14
- end
15
-
16
- after :each do
17
- monitor.kill
18
- end
7
+ before { monitor }
8
+ after { monitor.kill }
19
9
 
20
10
  context 'old locks' do
21
11
  let(:timeout) { 0.5 }
@@ -1,8 +1,4 @@
1
- require 'spec_helper'
2
-
3
1
  RSpec.describe Sidekiq::LimitFetch::Queues do
4
- subject { described_class.new options }
5
-
6
2
  let(:queues) { %w[queue1 queue2] }
7
3
  let(:limits) {{ 'queue1' => 3 }}
8
4
  let(:strict) { true }
@@ -14,10 +10,11 @@ RSpec.describe Sidekiq::LimitFetch::Queues do
14
10
  limits: limits,
15
11
  strict: strict,
16
12
  blocking: blocking,
17
- process_limits: process_limits,
18
- namespace: Sidekiq::LimitFetch::Redis.determine_namespace }
13
+ process_limits: process_limits }
19
14
  end
20
15
 
16
+ before { subject.start options }
17
+
21
18
  it 'should acquire queues' do
22
19
  subject.acquire
23
20
  expect(Sidekiq::Queue['queue1'].probed).to eq 1
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
1
  RSpec.describe 'semaphore' do
4
2
  let(:name) { 'default' }
5
3
  subject { Sidekiq::LimitFetch::Global::Semaphore.new name }
@@ -1,7 +1,7 @@
1
- require 'spec_helper'
1
+ Thread.abort_on_exception = true
2
2
 
3
3
  RSpec.describe Sidekiq::LimitFetch do
4
- before :each do
4
+ before do
5
5
  Sidekiq.redis do |it|
6
6
  it.del 'queue:queue1'
7
7
  it.lpush 'queue:queue1', 'task1'
@@ -10,11 +10,12 @@ RSpec.describe Sidekiq::LimitFetch do
10
10
  end
11
11
  end
12
12
 
13
- subject { described_class.new options }
14
13
  let(:options) {{ queues: queues, limits: limits }}
15
14
  let(:queues) { %w(queue1 queue1 queue2 queue2) }
16
15
  let(:limits) {{ 'queue1' => 1, 'queue2' => 2 }}
17
16
 
17
+ before { subject::Queues.start options }
18
+
18
19
  it 'should acquire lock on queue for execution' do
19
20
  work = subject.retrieve_work
20
21
  expect(work.queue_name).to eq 'queue1'
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,4 @@
1
1
  require 'sidekiq/limit_fetch'
2
- require 'celluloid/autostart'
3
- require 'sidekiq/fetch'
4
2
 
5
3
  Sidekiq.logger = nil
6
4
  Sidekiq.redis = { namespace: ENV['namespace'] }
@@ -9,7 +7,7 @@ RSpec.configure do |config|
9
7
  config.order = :random
10
8
  config.disable_monkey_patching!
11
9
  config.raise_errors_for_deprecations!
12
- config.before :each do
10
+ config.before do
13
11
  Sidekiq::Queue.reset_instances!
14
12
  Sidekiq.redis do |it|
15
13
  clean_redis = ->(queue) do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-limit_fetch
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.2
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - brainopia
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-09 00:00:00.000000000 Z
11
+ date: 2015-10-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sidekiq
@@ -16,34 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 2.6.5
20
- - - "<"
21
- - !ruby/object:Gem::Version
22
- version: '4.0'
19
+ version: '4'
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
24
  - - ">="
28
25
  - !ruby/object:Gem::Version
29
- version: 2.6.5
30
- - - "<"
31
- - !ruby/object:Gem::Version
32
- version: '4.0'
26
+ version: '4'
33
27
  - !ruby/object:Gem::Dependency
34
28
  name: rspec
35
29
  requirement: !ruby/object:Gem::Requirement
36
30
  requirements:
37
- - - "~>"
31
+ - - ">="
38
32
  - !ruby/object:Gem::Version
39
- version: 3.2.0
33
+ version: '0'
40
34
  type: :development
41
35
  prerelease: false
42
36
  version_requirements: !ruby/object:Gem::Requirement
43
37
  requirements:
44
- - - "~>"
38
+ - - ">="
45
39
  - !ruby/object:Gem::Version
46
- version: 3.2.0
40
+ version: '0'
47
41
  - !ruby/object:Gem::Dependency
48
42
  name: rake
49
43
  requirement: !ruby/object:Gem::Requirement
@@ -67,6 +61,7 @@ extensions: []
67
61
  extra_rdoc_files: []
68
62
  files:
69
63
  - ".gitignore"
64
+ - ".rspec"
70
65
  - ".travis.yml"
71
66
  - Gemfile
72
67
  - LICENSE.txt
@@ -86,14 +81,14 @@ files:
86
81
  - demo/config/environment.rb
87
82
  - demo/config/environments/development.rb
88
83
  - lib/sidekiq-limit_fetch.rb
84
+ - lib/sidekiq/extensions/manager.rb
89
85
  - lib/sidekiq/extensions/queue.rb
90
86
  - lib/sidekiq/limit_fetch.rb
91
87
  - lib/sidekiq/limit_fetch/global/monitor.rb
92
88
  - lib/sidekiq/limit_fetch/global/selector.rb
93
89
  - lib/sidekiq/limit_fetch/global/semaphore.rb
90
+ - lib/sidekiq/limit_fetch/instances.rb
94
91
  - lib/sidekiq/limit_fetch/queues.rb
95
- - lib/sidekiq/limit_fetch/redis.rb
96
- - lib/sidekiq/limit_fetch/singleton.rb
97
92
  - lib/sidekiq/limit_fetch/unit_of_work.rb
98
93
  - sidekiq-limit_fetch.gemspec
99
94
  - spec/sidekiq/extensions/queue_spec.rb
@@ -1,35 +0,0 @@
1
- module Sidekiq::LimitFetch::Redis
2
- extend self
3
-
4
- def nonblocking_redis
5
- redis do |redis|
6
- # Celluloid 0.16 broke this method
7
- if Celluloid::VERSION.to_f >= 0.16
8
- yield redis
9
- else
10
- # prevent blocking of fetcher
11
- # more bullet-proof and faster (O_O)
12
- # than using Celluloid::IO
13
- #
14
- # https://github.com/brainopia/sidekiq-limit_fetch/issues/41
15
- # explanation of why Future#value is beneficial here
16
- begin
17
- Celluloid::Future.new { yield redis }.value
18
- rescue Celluloid::Task::TerminatedError
19
- end
20
- end
21
- end
22
- end
23
-
24
- def redis
25
- Sidekiq.redis {|it| yield it }
26
- end
27
-
28
- def determine_namespace
29
- redis do |it|
30
- if it.respond_to?(:namespace) and it.namespace
31
- it.namespace + ':'
32
- end
33
- end
34
- end
35
- end