sidekiq-throttled 0.18.0 → 1.0.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|