sidekiq-throttled 0.18.0 → 1.0.0.alpha
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 +4 -4
- data/{README.md → README.adoc} +95 -114
- data/lib/sidekiq/throttled/basic_fetch.rb +55 -0
- data/lib/sidekiq/throttled/fetch.rb +3 -87
- data/lib/sidekiq/throttled/job.rb +1 -1
- data/lib/sidekiq/throttled/middleware.rb +3 -1
- data/lib/sidekiq/throttled/registry.rb +2 -5
- data/lib/sidekiq/throttled/strategy/concurrency.rb +2 -4
- data/lib/sidekiq/throttled/strategy/threshold.rb +2 -4
- data/lib/sidekiq/throttled/strategy.rb +10 -10
- data/lib/sidekiq/throttled/strategy_collection.rb +1 -1
- data/lib/sidekiq/throttled/version.rb +1 -1
- data/lib/sidekiq/throttled/web.rb +2 -45
- data/lib/sidekiq/throttled/worker.rb +1 -1
- data/lib/sidekiq/throttled.rb +16 -50
- metadata +17 -77
- data/.coveralls.yml +0 -1
- data/.github/dependabot.yml +0 -12
- data/.github/workflows/ci.yml +0 -52
- data/.gitignore +0 -12
- data/.rspec +0 -5
- data/.rubocop.yml +0 -20
- data/.rubocop_todo.yml +0 -68
- data/.travis.yml +0 -37
- data/.yardopts +0 -1
- data/Appraisals +0 -9
- data/CHANGES.md +0 -318
- data/Gemfile +0 -34
- data/Guardfile +0 -25
- data/Rakefile +0 -27
- data/gemfiles/sidekiq_6.4.gemfile +0 -33
- data/gemfiles/sidekiq_6.5.gemfile +0 -33
- data/lib/sidekiq/throttled/communicator/callbacks.rb +0 -72
- data/lib/sidekiq/throttled/communicator/exception_handler.rb +0 -25
- data/lib/sidekiq/throttled/communicator/listener.rb +0 -109
- data/lib/sidekiq/throttled/communicator.rb +0 -116
- data/lib/sidekiq/throttled/expirable_list.rb +0 -70
- data/lib/sidekiq/throttled/fetch/unit_of_work.rb +0 -83
- data/lib/sidekiq/throttled/patches/queue.rb +0 -18
- data/lib/sidekiq/throttled/queue_name.rb +0 -46
- data/lib/sidekiq/throttled/queues_pauser.rb +0 -152
- data/lib/sidekiq/throttled/testing.rb +0 -12
- data/lib/sidekiq/throttled/utils.rb +0 -19
- data/lib/sidekiq/throttled/web/queues.html.erb +0 -49
- data/lib/sidekiq/throttled/web/summary_fix.js +0 -10
- data/lib/sidekiq/throttled/web/summary_fix.rb +0 -35
- data/rubocop/layout.yml +0 -24
- data/rubocop/lint.yml +0 -41
- data/rubocop/metrics.yml +0 -4
- data/rubocop/performance.yml +0 -25
- data/rubocop/rspec.yml +0 -3
- data/rubocop/style.yml +0 -84
- data/sidekiq-throttled.gemspec +0 -36
- /data/{LICENSE.md → LICENSE} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7659ca0e722a87bc85f4e9d73a38075cf005b72515bbaf06604eabaab77d8fdd
|
4
|
+
data.tar.gz: 28c53a85bb5d346d09d8ec08c6d23cecc687b6ec35e4c9779c07eba32bc635d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b03a9d8f51981c778c4a7b0fb84d7c20dabf902eefb00518a98a4c5a028119e820cd93920946516a51e0a399e05cf2692d12e7b59b814b37045b4dc6f852c43
|
7
|
+
data.tar.gz: 37478b95ae4f5426f82dceec1aa918722772c9a2c785b7c94420460b897c52cc0eee1cce02f5d03214c5d28113c3c798f5c13e31fb342ae935d92a07bc60f9b7
|
data/{README.md → README.adoc}
RENAMED
@@ -1,37 +1,51 @@
|
|
1
|
-
|
1
|
+
= Sidekiq::Throttled
|
2
|
+
:ci-link: https://github.com/ixti/sidekiq-throttled/actions/workflows/ci.yml
|
3
|
+
:ci-badge: https://img.shields.io/github/actions/workflow/status/ixti/sidekiq-throttled/ci.yml?branch=main&style=for-the-badge
|
4
|
+
:gem-link: http://rubygems.org/gems/sidekiq-throttled
|
5
|
+
:gem-badge: https://img.shields.io/gem/v/sidekiq-throttled?style=for-the-badge
|
6
|
+
:doc-link: http://www.rubydoc.info/gems/sidekiq-throttled
|
7
|
+
:doc-badge: https://img.shields.io/badge/Documentation-API-blue?style=for-the-badge
|
2
8
|
|
3
|
-
|
4
|
-
[
|
5
|
-
[
|
9
|
+
****
|
10
|
+
{ci-link}[image:{ci-badge}[CI Status]]
|
11
|
+
{gem-link}[image:{gem-badge}[Latest Version]]
|
12
|
+
{doc-link}[image:{doc-badge}[API Documentation]]
|
13
|
+
****
|
6
14
|
|
7
|
-
|
15
|
+
NOTE: This is the 1.x *development* branch. For the 0.x *stable* branch, please
|
16
|
+
see: https://github.com/ixti/sidekiq-throttled/tree/0-x-stable[0-x-stable]
|
8
17
|
|
9
|
-
|
18
|
+
Concurrency and threshold throttling for https://github.com/mperham/sidekiq[Sidekiq].
|
19
|
+
|
20
|
+
|
21
|
+
== Installation
|
10
22
|
|
11
23
|
Add this line to your application's Gemfile:
|
12
24
|
|
13
|
-
|
25
|
+
[source,ruby]
|
26
|
+
----
|
14
27
|
gem "sidekiq-throttled"
|
15
|
-
|
28
|
+
----
|
16
29
|
|
17
30
|
And then execute:
|
18
31
|
|
19
|
-
|
32
|
+
$ bundle
|
20
33
|
|
21
34
|
Or install it yourself as:
|
22
35
|
|
23
|
-
|
36
|
+
$ gem install sidekiq-throttled
|
24
37
|
|
25
38
|
|
26
|
-
|
39
|
+
== Usage
|
27
40
|
|
28
41
|
Add somewhere in your app's bootstrap (e.g. `config/initializers/sidekiq.rb` if
|
29
42
|
you are using Rails):
|
30
43
|
|
31
|
-
|
44
|
+
[source,ruby]
|
45
|
+
----
|
32
46
|
require "sidekiq/throttled"
|
33
47
|
Sidekiq::Throttled.setup!
|
34
|
-
|
48
|
+
----
|
35
49
|
|
36
50
|
Load order can be an issue if you are using other Sidekiq plugins and/or middleware.
|
37
51
|
To prevent any problems, add the `.setup!` call to the bottom of your init file.
|
@@ -39,7 +53,8 @@ To prevent any problems, add the `.setup!` call to the bottom of your init file.
|
|
39
53
|
Once you've done that you can include `Sidekiq::Throttled::Job` to your
|
40
54
|
job classes and configure throttling:
|
41
55
|
|
42
|
-
|
56
|
+
[source,ruby]
|
57
|
+
----
|
43
58
|
class MyJob
|
44
59
|
include Sidekiq::Job
|
45
60
|
include Sidekiq::Throttled::Job
|
@@ -48,37 +63,39 @@ class MyJob
|
|
48
63
|
|
49
64
|
sidekiq_throttle(
|
50
65
|
# Allow maximum 10 concurrent jobs of this class at a time.
|
51
|
-
:
|
66
|
+
concurrency: { limit: 10 },
|
52
67
|
# Allow maximum 1K jobs being processed within one hour window.
|
53
|
-
:
|
68
|
+
threshold: { limit: 1_000, period: 1.hour }
|
54
69
|
)
|
55
70
|
|
56
71
|
def perform
|
57
72
|
# ...
|
58
73
|
end
|
59
74
|
end
|
60
|
-
|
75
|
+
----
|
61
76
|
|
62
|
-
|
63
|
-
thus if you're using Sidekiq
|
64
|
-
|
77
|
+
TIP: `Sidekiq::Throttled::Job` is aliased as `Sidekiq::Throttled::Worker`,
|
78
|
+
thus if you're using `Sidekiq::Worker` naming convention, you can use the
|
79
|
+
alias for consistency:
|
65
80
|
|
66
|
-
|
81
|
+
[source,ruby]
|
82
|
+
----
|
67
83
|
class MyWorker
|
68
84
|
include Sidekiq::Worker
|
69
85
|
include Sidekiq::Throttled::Worker
|
70
86
|
|
71
87
|
# ...
|
72
88
|
end
|
73
|
-
|
89
|
+
----
|
74
90
|
|
75
91
|
|
76
|
-
|
92
|
+
=== Observer
|
77
93
|
|
78
94
|
You can specify an observer that will be called on throttling. To do so pass an
|
79
95
|
`:observer` option with callable object:
|
80
96
|
|
81
|
-
|
97
|
+
[source,ruby]
|
98
|
+
----
|
82
99
|
class MyJob
|
83
100
|
include Sidekiq::Job
|
84
101
|
include Sidekiq::Throttled::Job
|
@@ -87,91 +104,95 @@ class MyJob
|
|
87
104
|
# do something
|
88
105
|
end
|
89
106
|
|
90
|
-
sidekiq_options :
|
107
|
+
sidekiq_options queue: :my_queue
|
91
108
|
|
92
109
|
sidekiq_throttle(
|
93
|
-
:
|
94
|
-
:
|
95
|
-
:
|
110
|
+
concurrency: { limit: 10 },
|
111
|
+
threshold: { limit: 100, period: 1.hour },
|
112
|
+
observer: MY_OBSERVER
|
96
113
|
)
|
97
114
|
|
98
115
|
def perform(*args)
|
99
116
|
# ...
|
100
117
|
end
|
101
118
|
end
|
102
|
-
|
119
|
+
----
|
103
120
|
|
104
121
|
Observer will receive `strategy, *args` arguments, where `strategy` is a Symbol
|
105
122
|
`:concurrency` or `:threshold`, and `*args` are the arguments that were passed
|
106
123
|
to the job.
|
107
124
|
|
108
125
|
|
109
|
-
|
126
|
+
=== Dynamic throttling
|
110
127
|
|
111
128
|
You can throttle jobs dynamically with `:key_suffix` option:
|
112
129
|
|
113
|
-
|
130
|
+
[source,ruby]
|
131
|
+
----
|
114
132
|
class MyJob
|
115
133
|
include Sidekiq::Job
|
116
134
|
include Sidekiq::Throttled::Job
|
117
135
|
|
118
|
-
sidekiq_options :
|
136
|
+
sidekiq_options queue: :my_queue
|
119
137
|
|
120
138
|
sidekiq_throttle(
|
121
139
|
# Allow maximum 10 concurrent jobs per user at a time.
|
122
|
-
:
|
140
|
+
concurrency: { limit: 10, key_suffix: -> (user_id) { user_id } }
|
123
141
|
)
|
124
142
|
|
125
143
|
def perform(user_id)
|
126
144
|
# ...
|
127
145
|
end
|
128
146
|
end
|
129
|
-
|
147
|
+
----
|
130
148
|
|
131
149
|
You can also supply dynamic values for limits and periods by supplying a proc
|
132
150
|
for these values. The proc will be evaluated at the time the job is fetched
|
133
151
|
and will receive the same arguments that are passed to the job.
|
134
152
|
|
135
|
-
|
153
|
+
[source,ruby]
|
154
|
+
----
|
136
155
|
class MyJob
|
137
156
|
include Sidekiq::Job
|
138
157
|
include Sidekiq::Throttled::Job
|
139
158
|
|
140
|
-
sidekiq_options :
|
159
|
+
sidekiq_options queue: :my_queue
|
141
160
|
|
142
161
|
sidekiq_throttle(
|
143
162
|
# Allow maximum 1000 concurrent jobs of this class at a time for VIPs and 10 for all other users.
|
144
|
-
:
|
145
|
-
:
|
146
|
-
:
|
163
|
+
concurrency: {
|
164
|
+
limit: ->(user_id) { User.vip?(user_id) ? 1_000 : 10 },
|
165
|
+
key_suffix: ->(user_id) { User.vip?(user_id) ? "vip" : "std" }
|
147
166
|
},
|
148
167
|
# Allow 1000 jobs/hour to be processed for VIPs and 10/day for all others
|
149
|
-
:
|
150
|
-
:
|
151
|
-
:
|
152
|
-
:
|
168
|
+
threshold: {
|
169
|
+
limit: ->(user_id) { User.vip?(user_id) ? 1_000 : 10 },
|
170
|
+
period: ->(user_id) { User.vip?(user_id) ? 1.hour : 1.day },
|
171
|
+
key_suffix: ->(user_id) { User.vip?(user_id) ? "vip" : "std" }
|
172
|
+
}
|
153
173
|
)
|
154
174
|
|
155
175
|
def perform(user_id)
|
156
176
|
# ...
|
157
177
|
end
|
158
178
|
end
|
159
|
-
|
179
|
+
----
|
160
180
|
|
161
181
|
You also can use several different keys to throttle one worker.
|
162
182
|
|
163
|
-
|
183
|
+
[source,ruby]
|
184
|
+
----
|
164
185
|
class MyJob
|
165
186
|
include Sidekiq::Job
|
166
187
|
include Sidekiq::Throttled::Job
|
167
188
|
|
168
|
-
sidekiq_options :
|
189
|
+
sidekiq_options queue: :my_queue
|
169
190
|
|
170
191
|
sidekiq_throttle(
|
171
192
|
# Allow maximum 10 concurrent jobs per project at a time and maximum 2 jobs per user
|
172
|
-
:
|
173
|
-
{ :
|
174
|
-
{ :
|
193
|
+
concurrency: [
|
194
|
+
{ limit: 10, key_suffix: -> (project_id, user_id) { project_id } },
|
195
|
+
{ limit: 2, key_suffix: -> (project_id, user_id) { user_id } }
|
175
196
|
]
|
176
197
|
# For :threshold it works the same
|
177
198
|
)
|
@@ -180,14 +201,14 @@ class MyJob
|
|
180
201
|
# ...
|
181
202
|
end
|
182
203
|
end
|
183
|
-
|
204
|
+
----
|
184
205
|
|
185
|
-
|
186
|
-
if you are using dynamic limit/period options. Otherwise you risk
|
187
|
-
some trouble.
|
206
|
+
IMPORTANT: Don't forget to specify `:key_suffix` and make it return different
|
207
|
+
values if you are using dynamic limit/period options. Otherwise, you risk
|
208
|
+
getting into some trouble.
|
188
209
|
|
189
210
|
|
190
|
-
|
211
|
+
=== Concurrency throttling fine-tuning
|
191
212
|
|
192
213
|
Concurrency throttling is based on distributed locks. Those locks have default
|
193
214
|
time to live (TTL) set to 15 minutes. If your job takes more than 15 minutes
|
@@ -200,53 +221,21 @@ OOM-killed) cleanup middleware wasn't executed and locks were not released.
|
|
200
221
|
If your job takes more than 15 minutes to complete, you can tune concurrency
|
201
222
|
lock TTL to fit your needs:
|
202
223
|
|
203
|
-
|
224
|
+
[source,ruby]
|
225
|
+
----
|
204
226
|
# Set concurrency strategy lock TTL to 1 hour.
|
205
|
-
sidekiq_throttle(:
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
## Enhanced Queues list
|
210
|
-
|
211
|
-
This gem provides ability to pause/resume queues from processing by workers.
|
212
|
-
So you may simply pause particular queue without need to stop and reconfigure
|
213
|
-
workers by simply pushing a button on sidekiq web UI.
|
214
|
-
|
215
|
-
By default we add *Enhanced Queues* tab with this functionality. But if you
|
216
|
-
want you can override default *Queues* tab completely (notice that page will
|
217
|
-
still be available using it's URL, but tab will be pointing enhanced version).
|
218
|
-
To do so, just call `Sidekiq::Throttled::Web.enhance_queues_tab!` somewhere
|
219
|
-
in your initializer/bootstrap code. If you are using rails, you might want to
|
220
|
-
add it right into your `config/routes.rb` file:
|
221
|
-
|
222
|
-
``` ruby
|
223
|
-
# file config/routes.rb
|
224
|
-
|
225
|
-
require "sidekiq/web"
|
226
|
-
require "sidekiq/throttled/web"
|
227
|
-
|
228
|
-
Rails.application.routes.draw do
|
229
|
-
# ...
|
227
|
+
sidekiq_throttle(concurrency: { limit: 20, ttl: 1.hour.to_i })
|
228
|
+
----
|
230
229
|
|
231
|
-
# Replace Sidekiq Queues with enhanced version!
|
232
|
-
Sidekiq::Throttled::Web.enhance_queues_tab!
|
233
230
|
|
234
|
-
|
235
|
-
mount Sidekiq::Web => "/sidekiq"
|
231
|
+
== Supported Ruby Versions
|
236
232
|
|
237
|
-
|
238
|
-
end
|
239
|
-
```
|
240
|
-
|
241
|
-
|
242
|
-
## Supported Ruby Versions
|
243
|
-
|
244
|
-
This library aims to support and is [tested against][ci] the following Ruby
|
245
|
-
versions:
|
233
|
+
This library aims to support and is tested against the following Ruby versions:
|
246
234
|
|
247
235
|
* Ruby 2.7.x
|
248
236
|
* Ruby 3.0.x
|
249
237
|
* Ruby 3.1.x
|
238
|
+
* Ruby 3.2.x
|
250
239
|
|
251
240
|
If something doesn't work on one of these versions, it's a bug.
|
252
241
|
|
@@ -262,15 +251,24 @@ exist at the time of a major release, support for that Ruby version may be
|
|
262
251
|
dropped.
|
263
252
|
|
264
253
|
|
265
|
-
|
254
|
+
== Supported Sidekiq Versions
|
266
255
|
|
267
|
-
This library aims to support work with following
|
256
|
+
This library aims to support and work with following Sidekiq versions:
|
268
257
|
|
269
|
-
* Sidekiq 6.4.x
|
270
258
|
* Sidekiq 6.5.x
|
259
|
+
* Sidekiq 7.0.x
|
260
|
+
* Sidekiq 7.1.x
|
261
|
+
|
262
|
+
|
263
|
+
== Development
|
271
264
|
|
265
|
+
bundle install
|
266
|
+
bundle exec appraisal generate
|
267
|
+
bundle exec appraisal install
|
268
|
+
bundle exec rake
|
272
269
|
|
273
|
-
|
270
|
+
|
271
|
+
== Contributing
|
274
272
|
|
275
273
|
* Fork sidekiq-throttled on GitHub
|
276
274
|
* Make your changes
|
@@ -278,20 +276,3 @@ This library aims to support work with following [Sidekiq][sidekiq] versions:
|
|
278
276
|
* Send a pull request
|
279
277
|
* If we like them we'll merge them
|
280
278
|
* If we've accepted a patch, feel free to ask for commit access!
|
281
|
-
|
282
|
-
|
283
|
-
## Development
|
284
|
-
|
285
|
-
```
|
286
|
-
bundle update
|
287
|
-
bundle exec appraisal install # install dependencies for all gemfiles
|
288
|
-
bundle exec appraisal update # update dependencies for all gemfiles
|
289
|
-
bundle exec appraisal rspec # run rspec against each gemfile
|
290
|
-
bundle exec rubocop # run static code analysis
|
291
|
-
```
|
292
|
-
|
293
|
-
Don't forget to run `appraisal update` after any changes to `Gemfile`.
|
294
|
-
|
295
|
-
|
296
|
-
[ci]: https://github.com/ixti/sidekiq-throttled/actions/workflows/ci.yml
|
297
|
-
[sidekiq]: https://github.com/mperham/sidekiq
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "sidekiq"
|
4
|
+
require "sidekiq/fetch"
|
5
|
+
|
6
|
+
module Sidekiq
|
7
|
+
module Throttled
|
8
|
+
# Default Sidekiq's BasicFetch infused with Throttler.
|
9
|
+
#
|
10
|
+
# @private
|
11
|
+
class BasicFetch < Sidekiq::BasicFetch
|
12
|
+
# Retrieves job from redis.
|
13
|
+
#
|
14
|
+
# @return [Sidekiq::Throttled::UnitOfWork, nil]
|
15
|
+
def retrieve_work
|
16
|
+
work = super
|
17
|
+
|
18
|
+
if work && Throttled.throttled?(work.job)
|
19
|
+
requeue_throttled(work)
|
20
|
+
return nil
|
21
|
+
end
|
22
|
+
|
23
|
+
work
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# Pushes job back to the head of the queue, so that job won't be tried
|
29
|
+
# immediately after it was requeued (in most cases).
|
30
|
+
#
|
31
|
+
# @note This is triggered when job is throttled. So it is same operation
|
32
|
+
# Sidekiq performs upon `Sidekiq::Worker.perform_async` call.
|
33
|
+
#
|
34
|
+
# @return [void]
|
35
|
+
def requeue_throttled(work)
|
36
|
+
redis { |conn| conn.lpush(work.queue, work.job) }
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns list of queues to try to fetch jobs from.
|
40
|
+
#
|
41
|
+
# @note It may return an empty array.
|
42
|
+
# @param [Array<String>] queues
|
43
|
+
# @return [Array<String>]
|
44
|
+
def queues_cmd
|
45
|
+
queues = super
|
46
|
+
|
47
|
+
# TODO: Refactor to be prepended as an integration mixin during configuration stage
|
48
|
+
# Or via configurable queues reducer
|
49
|
+
queues -= Sidekiq::Pauzer.paused_queues.map { |name| "queue:#{name}" } if defined?(Sidekiq::Pauzer)
|
50
|
+
|
51
|
+
queues
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -1,94 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
require "sidekiq/throttled/expirable_list"
|
5
|
-
require "sidekiq/throttled/fetch/unit_of_work"
|
6
|
-
require "sidekiq/throttled/queues_pauser"
|
7
|
-
require "sidekiq/throttled/queue_name"
|
3
|
+
require_relative "./basic_fetch"
|
8
4
|
|
9
5
|
module Sidekiq
|
10
6
|
module Throttled
|
11
|
-
#
|
12
|
-
|
13
|
-
# @private
|
14
|
-
class Fetch
|
15
|
-
# Timeout to sleep between fetch retries in case of no job received,
|
16
|
-
# as well as timeout to wait for redis to give us something to work.
|
17
|
-
TIMEOUT = 2
|
18
|
-
|
19
|
-
# Initializes fetcher instance.
|
20
|
-
# @param options [Hash]
|
21
|
-
# @option options [Integer] :throttled_queue_cooldown (TIMEOUT)
|
22
|
-
# Min delay in seconds before queue will be polled again after
|
23
|
-
# throttled job.
|
24
|
-
# @option options [Boolean] :strict (false)
|
25
|
-
# @option options [Array<#to_s>] :queue
|
26
|
-
def initialize(options)
|
27
|
-
@paused = ExpirableList.new(options.fetch(:throttled_queue_cooldown, TIMEOUT))
|
28
|
-
|
29
|
-
@strict = options.fetch(:strict, false)
|
30
|
-
@queues = options.fetch(:queues).map { |q| QueueName.expand q }
|
31
|
-
|
32
|
-
raise ArgumentError, "empty :queues" if @queues.empty?
|
33
|
-
|
34
|
-
@queues.uniq! if @strict
|
35
|
-
end
|
36
|
-
|
37
|
-
# Retrieves job from redis.
|
38
|
-
#
|
39
|
-
# @return [Sidekiq::Throttled::UnitOfWork, nil]
|
40
|
-
def retrieve_work
|
41
|
-
work = brpop
|
42
|
-
return unless work
|
43
|
-
|
44
|
-
work = UnitOfWork.new(*work)
|
45
|
-
return work unless work.throttled?
|
46
|
-
|
47
|
-
work.requeue_throttled
|
48
|
-
@paused << QueueName.expand(work.queue_name)
|
49
|
-
|
50
|
-
nil
|
51
|
-
end
|
52
|
-
|
53
|
-
def bulk_requeue(units, _options)
|
54
|
-
return if units.empty?
|
55
|
-
|
56
|
-
Sidekiq.logger.debug { "Re-queueing terminated jobs" }
|
57
|
-
Sidekiq.redis do |conn|
|
58
|
-
conn.pipelined do |pipeline|
|
59
|
-
units.each { |unit| unit.requeue(pipeline) }
|
60
|
-
end
|
61
|
-
end
|
62
|
-
Sidekiq.logger.info("Pushed #{units.size} jobs back to Redis")
|
63
|
-
rescue => e
|
64
|
-
Sidekiq.logger.warn("Failed to requeue #{units.size} jobs: #{e}")
|
65
|
-
end
|
66
|
-
|
67
|
-
private
|
68
|
-
|
69
|
-
# Tries to pop pair of `queue` and job `message` out of sidekiq queues.
|
70
|
-
#
|
71
|
-
# @see http://redis.io/commands/brpop
|
72
|
-
# @return [Array(String, String), nil]
|
73
|
-
def brpop
|
74
|
-
queues = filter_queues(@strict ? @queues : @queues.shuffle.uniq)
|
75
|
-
|
76
|
-
if queues.empty?
|
77
|
-
sleep TIMEOUT
|
78
|
-
return
|
79
|
-
end
|
80
|
-
|
81
|
-
Sidekiq.redis { |conn| conn.brpop(*queues, :timeout => TIMEOUT) }
|
82
|
-
end
|
83
|
-
|
84
|
-
# Returns list of queues to try to fetch jobs from.
|
85
|
-
#
|
86
|
-
# @note It may return an empty array.
|
87
|
-
# @param [Array<String>] queues
|
88
|
-
# @return [Array<String>]
|
89
|
-
def filter_queues(queues)
|
90
|
-
QueuesPauser.instance.filter(queues) - @paused.to_a
|
91
|
-
end
|
92
|
-
end
|
7
|
+
# @deprecated Use Sidekiq::Throttled::BasicFetch
|
8
|
+
Fetch = BasicFetch
|
93
9
|
end
|
94
10
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# internal
|
4
|
-
|
4
|
+
require_relative "./registry"
|
5
5
|
|
6
6
|
module Sidekiq
|
7
7
|
module Throttled
|
@@ -9,6 +9,8 @@ module Sidekiq
|
|
9
9
|
#
|
10
10
|
# @private
|
11
11
|
class Middleware
|
12
|
+
include Sidekiq::ServerMiddleware if Sidekiq::VERSION >= "6.5.0"
|
13
|
+
|
12
14
|
# Called within Sidekiq job processing
|
13
15
|
def call(_worker, msg, _queue)
|
14
16
|
yield
|
@@ -1,8 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# internal
|
4
|
-
|
5
|
-
require "sidekiq/throttled/utils"
|
4
|
+
require_relative "./strategy"
|
6
5
|
|
7
6
|
module Sidekiq
|
8
7
|
module Throttled
|
@@ -14,8 +13,6 @@ module Sidekiq
|
|
14
13
|
@aliases = {}
|
15
14
|
|
16
15
|
class << self
|
17
|
-
include Utils
|
18
|
-
|
19
16
|
# Adds strategy to the registry.
|
20
17
|
#
|
21
18
|
# @param (see Strategy#initialize)
|
@@ -107,7 +104,7 @@ module Sidekiq
|
|
107
104
|
def find_by_class(name)
|
108
105
|
return unless Throttled.configuration.inherit_strategies?
|
109
106
|
|
110
|
-
const = name.is_a?(Class) ? name :
|
107
|
+
const = name.is_a?(Class) ? name : Object.const_get(name)
|
111
108
|
return unless const.is_a?(Class)
|
112
109
|
|
113
110
|
const.ancestors.each do |m|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require "redis_prescription"
|
4
4
|
|
5
|
-
|
5
|
+
require_relative "./base"
|
6
6
|
|
7
7
|
module Sidekiq
|
8
8
|
module Throttled
|
@@ -49,9 +49,7 @@ module Sidekiq
|
|
49
49
|
keys = [key(job_args)]
|
50
50
|
argv = [jid.to_s, job_limit, @ttl, Time.now.to_f]
|
51
51
|
|
52
|
-
Sidekiq.redis
|
53
|
-
1 == SCRIPT.call(redis, :keys => keys, :argv => argv)
|
54
|
-
end
|
52
|
+
Sidekiq.redis { |redis| 1 == SCRIPT.call(redis, keys: keys, argv: argv) }
|
55
53
|
end
|
56
54
|
|
57
55
|
# @return [Integer] Current count of jobs
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require "redis_prescription"
|
4
4
|
|
5
|
-
|
5
|
+
require_relative "./base"
|
6
6
|
|
7
7
|
module Sidekiq
|
8
8
|
module Throttled
|
@@ -66,9 +66,7 @@ module Sidekiq
|
|
66
66
|
keys = [key(job_args)]
|
67
67
|
argv = [job_limit, period(job_args), Time.now.to_f]
|
68
68
|
|
69
|
-
Sidekiq.redis
|
70
|
-
1 == SCRIPT.call(redis, :keys => keys, :argv => argv)
|
71
|
-
end
|
69
|
+
Sidekiq.redis { |redis| 1 == SCRIPT.call(redis, keys: keys, argv: argv) }
|
72
70
|
end
|
73
71
|
|
74
72
|
# @return [Integer] Current count of jobs
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# internal
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
require_relative "./errors"
|
5
|
+
require_relative "./strategy_collection"
|
6
|
+
require_relative "./strategy/concurrency"
|
7
|
+
require_relative "./strategy/threshold"
|
8
8
|
|
9
9
|
module Sidekiq
|
10
10
|
module Throttled
|
@@ -35,14 +35,14 @@ module Sidekiq
|
|
35
35
|
@observer = observer
|
36
36
|
|
37
37
|
@concurrency = StrategyCollection.new(concurrency,
|
38
|
-
:
|
39
|
-
:
|
40
|
-
:
|
38
|
+
strategy: Concurrency,
|
39
|
+
name: name,
|
40
|
+
key_suffix: key_suffix)
|
41
41
|
|
42
42
|
@threshold = StrategyCollection.new(threshold,
|
43
|
-
:
|
44
|
-
:
|
45
|
-
:
|
43
|
+
strategy: Threshold,
|
44
|
+
name: name,
|
45
|
+
key_suffix: key_suffix)
|
46
46
|
|
47
47
|
return if @concurrency.any? || @threshold.any?
|
48
48
|
|