sidekiq-limit_fetch 4.0.0 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 88e19126b173869fae0b5046533e8615d2785fb903f01b979cbcdea65e7824b5
4
- data.tar.gz: 212cfdcf179fa2aceb6eb065e7bd384109f3afbf2ff08da27699197a300cf044
3
+ metadata.gz: f4e35bb2ed507c01ab307ba39254c5d82ba6837d60a771c33e765f3a92ede831
4
+ data.tar.gz: 3883ea7ccd095c1f9f0f3ae3900d642500e14f146a74b37a9cffd48440e4e6ec
5
5
  SHA512:
6
- metadata.gz: 0f0c99a5e6d183f9ce41c7bfd85f74926efad1515f29d88d24c7c1076b108121ed9c963ea60d76406c4a006e9b49dcb09239d9fe5b14e59e8f3702b7e4591689
7
- data.tar.gz: 888322ef2940592c4d65095b136a4a4cf27cfe7f9bb470cb071fe3a47028cd095fc9b4c30392cb3d25be26536126851f357a61f6b31145dfb31add97f9250bec
6
+ metadata.gz: b1ae9ec40f0f303c352579478a75c7d85cf1fb77fa5f48f73bd2d44b35dd1d6e9daf1f88251108990408a1efc6077f3b250a571ff3d2806de9a72a2766d033b3
7
+ data.tar.gz: 9ace46d937a68560dc050fee75ebd4ce663f17bce4ea1be25825d568816282b8ce6059133786e8463fe48d3349baffb4c7a93e04613568367e9114672d23f314
data/CHANGELOG.md ADDED
@@ -0,0 +1,22 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [4.1.0] - 2022-03-29
9
+
10
+ ### Changed
11
+
12
+ - #101 - Fix stuck queues bug on Redis restart from [@907th](https://github.com/907th).
13
+
14
+ ## [4.0.0] - 2022-03-26
15
+
16
+ This project was taken over by [@deanpcmad](https://github.com/deanpcmad)
17
+
18
+ ### Changed
19
+
20
+ - #120 - Migrate CI to GitHub Actions from [@petergoldstein](https://github.com/petergoldstein).
21
+ - #124 - Fixed redis v4.6.0 pipelines deprecation warning from [@iurev](https://github.com/iurev).
22
+ - #83 - Processing dynamic queues from [@alexey-yanchenko](https://github.com/alexey-yanchenko).
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Dean Perry
4
+ Copyright (c) 2013 brainopia
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ## Description
2
2
 
3
- *This project is currently being taken over by [@deanpcmad](https://github.com/deanpcmad) and will be updated soon*
3
+ *This project has been taken over by [@deanpcmad](https://github.com/deanpcmad)*
4
4
 
5
5
  Sidekiq strategy to support a granular queue control – limiting, pausing, blocking, querying.
6
6
 
@@ -11,7 +11,11 @@ Sidekiq strategy to support a granular queue control – limiting, pausing, bloc
11
11
 
12
12
  Add this line to your application's Gemfile:
13
13
 
14
- gem 'sidekiq-limit_fetch'
14
+ ```
15
+ gem 'sidekiq-limit_fetch'
16
+ ```
17
+
18
+ Then `bundle install`.
15
19
 
16
20
  ### Limitations
17
21
 
@@ -31,19 +35,19 @@ To use this Gem in other Ruby projects, just add `require 'sidekiq-limit_fetch'`
31
35
  Specify limits which you want to place on queues inside sidekiq.yml:
32
36
 
33
37
  ```yaml
34
- :limits:
35
- queue_name1: 5
36
- queue_name2: 10
38
+ :limits:
39
+ queue_name1: 5
40
+ queue_name2: 10
37
41
  ```
38
42
 
39
43
  Or set it dynamically in your code:
40
44
  ```ruby
41
- Sidekiq::Queue['queue_name1'].limit = 5
42
- Sidekiq::Queue['queue_name2'].limit = 10
45
+ Sidekiq::Queue['queue_name1'].limit = 5
46
+ Sidekiq::Queue['queue_name2'].limit = 10
43
47
  ```
44
48
 
45
- In these examples, tasks for the ```queue_name1``` will be run by at most 5
46
- workers at the same time and the ```queue_name2``` will have no more than 10
49
+ In these examples, tasks for the `queue_name1` will be run by at most 5
50
+ workers at the same time and the `queue_name2` will have no more than 10
47
51
  workers simultaneously.
48
52
 
49
53
  Ability to set limits dynamically allows you to resize worker
@@ -54,14 +58,14 @@ distribution among queues any time you want.
54
58
  If you use multiple sidekiq processes then you can specify limits per process:
55
59
 
56
60
  ```yaml
57
- :process_limits:
58
- queue_name: 2
61
+ :process_limits:
62
+ queue_name: 2
59
63
  ```
60
64
 
61
65
  Or set it in your code:
62
66
 
63
67
  ```ruby
64
- Sidekiq::Queue['queue_name'].process_limit = 2
68
+ Sidekiq::Queue['queue_name'].process_limit = 2
65
69
  ```
66
70
 
67
71
  ### Busy workers by queue
@@ -69,7 +73,7 @@ Or set it in your code:
69
73
  You can see how many workers currently handling a queue:
70
74
 
71
75
  ```ruby
72
- Sidekiq::Queue['name'].busy # number of busy workers
76
+ Sidekiq::Queue['name'].busy # number of busy workers
73
77
  ```
74
78
 
75
79
  ### Pauses
@@ -78,10 +82,10 @@ You can also pause your queues temporarily. Upon continuing their limits
78
82
  will be preserved.
79
83
 
80
84
  ```ruby
81
- Sidekiq::Queue['name'].pause # prevents workers from running tasks from this queue
82
- Sidekiq::Queue['name'].paused? # => true
83
- Sidekiq::Queue['name'].unpause # allows workers to use the queue
84
- Sidekiq::Queue['name'].pause_for_ms(1000) # will pause for a second
85
+ Sidekiq::Queue['name'].pause # prevents workers from running tasks from this queue
86
+ Sidekiq::Queue['name'].paused? # => true
87
+ Sidekiq::Queue['name'].unpause # allows workers to use the queue
88
+ Sidekiq::Queue['name'].pause_for_ms(1000) # will pause for a second
85
89
  ```
86
90
 
87
91
  ### Blocking queue mode
@@ -92,12 +96,12 @@ queue task is executing then no new task from lesser priority queues will
92
96
  be ran. Eg,
93
97
 
94
98
  ```yaml
95
- :queues:
96
- - a
97
- - b
98
- - c
99
- :blocking:
100
- - b
99
+ :queues:
100
+ - a
101
+ - b
102
+ - c
103
+ :blocking:
104
+ - b
101
105
  ```
102
106
 
103
107
  In this case when a task for `b` queue is ran no new task from `c` queue
@@ -106,9 +110,9 @@ will be started.
106
110
  You can also enable and disable blocking mode for queues on the fly:
107
111
 
108
112
  ```ruby
109
- Sidekiq::Queue['name'].block
110
- Sidekiq::Queue['name'].blocking? # => true
111
- Sidekiq::Queue['name'].unblock
113
+ Sidekiq::Queue['name'].block
114
+ Sidekiq::Queue['name'].blocking? # => true
115
+ Sidekiq::Queue['name'].unblock
112
116
  ```
113
117
 
114
118
  ### Advanced blocking queues
@@ -118,13 +122,13 @@ running only queues higher and queues from their blocking group can
118
122
  run. It will be easier to understand with an example:
119
123
 
120
124
  ```yaml
121
- :queues:
122
- - a
123
- - b
124
- - c
125
- - d
126
- :blocking:
127
- - [b, c]
125
+ :queues:
126
+ - a
127
+ - b
128
+ - c
129
+ - d
130
+ :blocking:
131
+ - [b, c]
128
132
  ```
129
133
 
130
134
  In this case tasks from `d` will be blocked when a task from queue `b` or `c` is executed.
@@ -132,7 +136,7 @@ In this case tasks from `d` will be blocked when a task from queue `b` or `c` is
132
136
  You can dynamically set exceptions for queue blocking:
133
137
 
134
138
  ```ruby
135
- Sidekiq::Queue['queue1'].block_except 'queue2'
139
+ Sidekiq::Queue['queue1'].block_except 'queue2'
136
140
  ```
137
141
 
138
142
  ### Dynamic queues
@@ -143,11 +147,11 @@ that have tasks pushed to them (usually with `Sidekiq::Client.push`)).
143
147
  To use this mode you need to specify a following line in sidekiq.yml:
144
148
 
145
149
  ```yaml
146
- :dynamic: true
150
+ :dynamic: true
147
151
  ```
148
152
 
149
153
  Dynamic queues will be ran at the lowest priority.
150
154
 
151
155
  ### Maintenance
152
156
 
153
- If you use ```flushdb```, restart the sidekiq process to re-populate the dynamic configuration.
157
+ If you use `flushdb`, restart the sidekiq process to re-populate the dynamic configuration.
@@ -20,15 +20,17 @@ module Sidekiq::LimitFetch::Queues
20
20
  end
21
21
 
22
22
  def acquire
23
- selector.acquire(ordered_queues, namespace)
24
- .tap {|it| save it }
25
- .map {|it| "queue:#{it}" }
23
+ queues = saved
24
+ queues ||= Sidekiq::LimitFetch.redis_retryable do
25
+ selector.acquire(ordered_queues, namespace)
26
+ end
27
+ save queues
28
+ queues.map { |it| "queue:#{it}" }
26
29
  end
27
30
 
28
31
  def release_except(full_name)
29
32
  queues = restore
30
33
  queues.delete full_name[/queue:(.*)/, 1] if full_name
31
-
32
34
  Sidekiq::LimitFetch.redis_retryable do
33
35
  selector.release queues, namespace
34
36
  end
@@ -141,13 +143,17 @@ module Sidekiq::LimitFetch::Queues
141
143
  Sidekiq::LimitFetch::Global::Selector
142
144
  end
143
145
 
146
+ def saved
147
+ Thread.current[THREAD_KEY]
148
+ end
149
+
144
150
  def save(queues)
145
151
  Thread.current[THREAD_KEY] = queues
146
152
  end
147
153
 
148
154
  def restore
149
- Thread.current[THREAD_KEY] || []
155
+ saved || []
150
156
  ensure
151
- Thread.current[THREAD_KEY] = nil
157
+ save nil
152
158
  end
153
159
  end
@@ -14,6 +14,8 @@ module Sidekiq::LimitFetch
14
14
  require_relative 'extensions/queue'
15
15
  require_relative 'extensions/manager'
16
16
 
17
+ TIMEOUT = Sidekiq::BasicFetch::TIMEOUT
18
+
17
19
  extend self
18
20
 
19
21
  def new(_)
@@ -39,14 +41,21 @@ module Sidekiq::LimitFetch
39
41
  def redis_retryable
40
42
  yield
41
43
  rescue Redis::BaseConnectionError
42
- sleep 1
44
+ sleep TIMEOUT
43
45
  retry
46
+ rescue Redis::CommandError => error
47
+ # If Redis was restarted and is still loading its snapshot,
48
+ # then we should treat this as a temporary connection error too.
49
+ if error.message =~ /^LOADING/
50
+ sleep TIMEOUT
51
+ retry
52
+ else
53
+ raise
54
+ end
44
55
  end
45
56
 
46
57
  private
47
58
 
48
- TIMEOUT = Sidekiq::BasicFetch::TIMEOUT
49
-
50
59
  def redis_brpop(queues)
51
60
  if queues.empty?
52
61
  sleep TIMEOUT # there are no queues to handle, so lets sleep
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |gem|
2
2
  gem.name = 'sidekiq-limit_fetch'
3
- gem.version = '4.0.0'
3
+ gem.version = '4.1.0'
4
4
  gem.license = 'MIT'
5
5
  gem.authors = ['Dean Perry', 'brainopia']
6
6
  gem.email = 'dean@deanpcmad.com'
@@ -8,6 +8,10 @@ Gem::Specification.new do |gem|
8
8
  gem.homepage = 'https://github.com/deanpcmad/sidekiq-limit_fetch'
9
9
  gem.description = "Sidekiq strategy to restrict number of workers which are able to run specified queues simultaneously."
10
10
 
11
+ gem.metadata["homepage_uri"] = gem.homepage
12
+ gem.metadata["source_code_uri"] = "https://github.com/deanpcmad/sidekiq-limit_fetch"
13
+ gem.metadata["changelog_uri"] = "https://github.com/deanpcmad/sidekiq-limit_fetch/blob/master/CHANGELOG.md"
14
+
11
15
  gem.files = `git ls-files`.split($/)
12
16
  gem.test_files = gem.files.grep %r{^spec/}
13
17
  gem.require_paths = %w(lib)
@@ -15,61 +15,72 @@ RSpec.describe Sidekiq::LimitFetch::Queues do
15
15
 
16
16
  before { subject.start options }
17
17
 
18
+ def in_thread(&block)
19
+ thr = Thread.new(&block)
20
+ thr.join
21
+ end
22
+
18
23
  it 'should acquire queues' do
19
- subject.acquire
24
+ in_thread { subject.acquire }
20
25
  expect(Sidekiq::Queue['queue1'].probed).to eq 1
21
26
  expect(Sidekiq::Queue['queue2'].probed).to eq 1
22
27
  end
23
28
 
24
29
  it 'should acquire dynamically blocking queues' do
25
- subject.acquire
30
+ in_thread { subject.acquire }
26
31
  expect(Sidekiq::Queue['queue1'].probed).to eq 1
27
32
  expect(Sidekiq::Queue['queue2'].probed).to eq 1
28
33
 
29
34
  Sidekiq::Queue['queue1'].block
30
35
 
31
- subject.acquire
36
+ in_thread { subject.acquire }
32
37
  expect(Sidekiq::Queue['queue1'].probed).to eq 2
33
38
  expect(Sidekiq::Queue['queue2'].probed).to eq 1
34
39
  end
35
40
 
36
41
  it 'should block except given queues' do
37
42
  Sidekiq::Queue['queue1'].block_except 'queue2'
38
- subject.acquire
43
+ in_thread { subject.acquire }
39
44
  expect(Sidekiq::Queue['queue1'].probed).to eq 1
40
45
  expect(Sidekiq::Queue['queue2'].probed).to eq 1
41
46
 
42
47
  Sidekiq::Queue['queue1'].block_except 'queue404'
43
- subject.acquire
48
+ in_thread { subject.acquire }
44
49
  expect(Sidekiq::Queue['queue1'].probed).to eq 2
45
50
  expect(Sidekiq::Queue['queue2'].probed).to eq 1
46
51
  end
47
52
 
48
53
  it 'should release queues' do
49
- subject.acquire
50
- subject.release_except nil
54
+ in_thread {
55
+ subject.acquire
56
+ subject.release_except nil
57
+ }
51
58
  expect(Sidekiq::Queue['queue1'].probed).to eq 0
52
59
  expect(Sidekiq::Queue['queue2'].probed).to eq 0
53
60
  end
54
61
 
55
62
  it 'should release queues except selected' do
56
- subject.acquire
57
- subject.release_except 'queue:queue1'
63
+ in_thread {
64
+ subject.acquire
65
+ subject.release_except 'queue:queue1'
66
+ }
58
67
  expect(Sidekiq::Queue['queue1'].probed).to eq 1
59
68
  expect(Sidekiq::Queue['queue2'].probed).to eq 0
60
69
  end
61
70
 
62
71
  it 'should release when no queues was acquired' do
63
72
  queues.each {|name| Sidekiq::Queue[name].pause }
64
- subject.acquire
65
- expect { subject.release_except nil }.not_to raise_exception
73
+ in_thread {
74
+ subject.acquire
75
+ expect { subject.release_except nil }.not_to raise_exception
76
+ }
66
77
  end
67
78
 
68
79
  context 'blocking' do
69
80
  let(:blocking) { %w(queue1) }
70
81
 
71
82
  it 'should acquire blocking queues' do
72
- 3.times { subject.acquire }
83
+ 3.times { in_thread { subject.acquire } }
73
84
  expect(Sidekiq::Queue['queue1'].probed).to eq 3
74
85
  expect(Sidekiq::Queue['queue2'].probed).to eq 1
75
86
  end
@@ -6,7 +6,7 @@ RSpec.describe Sidekiq::LimitFetch do
6
6
  let(:limits) {{ 'queue1' => 1, 'queue2' => 2 }}
7
7
 
8
8
  before do
9
- subject::Queues.start options
9
+ subject::Queues.start options
10
10
 
11
11
  Sidekiq.redis do |it|
12
12
  it.del 'queue:queue1'
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: 4.0.0
4
+ version: 4.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dean Perry
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-03-26 00:00:00.000000000 Z
12
+ date: 2022-03-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sidekiq
@@ -112,8 +112,9 @@ files:
112
112
  - ".gitignore"
113
113
  - ".rspec"
114
114
  - Appraisals
115
+ - CHANGELOG.md
115
116
  - Gemfile
116
- - LICENSE.txt
117
+ - LICENSE
117
118
  - README.md
118
119
  - Rakefile
119
120
  - bench/compare.rb
@@ -167,7 +168,10 @@ files:
167
168
  homepage: https://github.com/deanpcmad/sidekiq-limit_fetch
168
169
  licenses:
169
170
  - MIT
170
- metadata: {}
171
+ metadata:
172
+ homepage_uri: https://github.com/deanpcmad/sidekiq-limit_fetch
173
+ source_code_uri: https://github.com/deanpcmad/sidekiq-limit_fetch
174
+ changelog_uri: https://github.com/deanpcmad/sidekiq-limit_fetch/blob/master/CHANGELOG.md
171
175
  post_install_message:
172
176
  rdoc_options: []
173
177
  require_paths:
@@ -183,7 +187,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
183
187
  - !ruby/object:Gem::Version
184
188
  version: '0'
185
189
  requirements: []
186
- rubygems_version: 3.1.6
190
+ rubygems_version: 3.2.22
187
191
  signing_key:
188
192
  specification_version: 4
189
193
  summary: Sidekiq strategy to support queue limits
data/LICENSE.txt DELETED
@@ -1,22 +0,0 @@
1
- Copyright (c) 2013 brainopia
2
-
3
- MIT License
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.