sidekiq-throttled 0.3.2 → 0.4.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 +4 -4
- data/CHANGES.md +8 -0
- data/README.md +37 -7
- data/lib/sidekiq/throttled/registry.rb +1 -1
- data/lib/sidekiq/throttled/strategy.rb +6 -3
- data/lib/sidekiq/throttled/strategy/concurrency.rb +14 -11
- data/lib/sidekiq/throttled/strategy/threshold.rb +23 -15
- data/lib/sidekiq/throttled/version.rb +1 -1
- data/lib/sidekiq/throttled/web/stats.rb +2 -2
- metadata +2 -3
- data/bin/setup +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b39d91ca9d489440aa46f943c0bfb4dafd977621
|
4
|
+
data.tar.gz: 754e0213ad9081a626f50d7711a4d8de7076e15e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba2a4dcb2313576ac14576740e53ec1e90fe1e71b9c2edc843ac744514ee550628d5b85a7351c835ba4786ec1aa61de173ee9ae98df9da6045dbb419bcc102f6
|
7
|
+
data.tar.gz: 5e07672a509a76896da044455a53569a57c9dca5bb017384fb1fdc1a6e97115a54c7d52351b75540a40b0d94763a1fbde1a120f52fb0a605922dcabd34d10eab
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
## 0.4.0 (2016-05-17)
|
2
|
+
|
3
|
+
* [#14](https://github.com/sensortower/sidekiq-throttled/pull/14)
|
4
|
+
Support dynamic configuration of limits and periods.
|
5
|
+
([@azach], [@ixti])
|
6
|
+
|
7
|
+
|
1
8
|
## 0.3.2 (2016-05-16)
|
2
9
|
|
3
10
|
* [#13](https://github.com/sensortower/sidekiq-throttled/issues/13)
|
@@ -34,3 +41,4 @@
|
|
34
41
|
[@ixti]: https://github.com/ixti
|
35
42
|
[@fhwang]: https://github.com/fhwang
|
36
43
|
[@palanglung]: https://github.com/palanglung
|
44
|
+
[@azach]: https://github.com/azach
|
data/README.md
CHANGED
@@ -12,21 +12,17 @@ Concurrency and threshold throttling for [Sidekiq](https://github.com/mperham/si
|
|
12
12
|
|
13
13
|
Add this line to your application's Gemfile:
|
14
14
|
|
15
|
-
```ruby
|
15
|
+
``` ruby
|
16
16
|
gem "sidekiq-throttled"
|
17
17
|
```
|
18
18
|
|
19
19
|
And then execute:
|
20
20
|
|
21
|
-
|
22
|
-
$ bundle
|
23
|
-
```
|
21
|
+
$ bundle
|
24
22
|
|
25
23
|
Or install it yourself as:
|
26
24
|
|
27
|
-
|
28
|
-
$ gem install sidekiq-throttled
|
29
|
-
```
|
25
|
+
$ gem install sidekiq-throttled
|
30
26
|
|
31
27
|
|
32
28
|
## Usage
|
@@ -85,6 +81,40 @@ class MyWorker
|
|
85
81
|
end
|
86
82
|
```
|
87
83
|
|
84
|
+
You can also supply dynamic values for limits and periods by supplying a proc
|
85
|
+
for these values. The proc will be evaluated at the time the job is fetched
|
86
|
+
and will receive the same arguments that are passed to the job.
|
87
|
+
|
88
|
+
``` ruby
|
89
|
+
class MyWorker
|
90
|
+
include Sidekiq::Worker
|
91
|
+
include Sidekiq::Throttled::Worker
|
92
|
+
|
93
|
+
sidekiq_options :queue => :my_queue
|
94
|
+
|
95
|
+
sidekiq_throttle({
|
96
|
+
# Allow maximum 1000 concurrent jobs of this class at a time for VIPs and 10 for all other users.
|
97
|
+
:concurrency => {
|
98
|
+
:limit => ->(user_id) { User.vip?(user_id) ? 1_000 : 10 },
|
99
|
+
:key_suffix => ->(user_id) { User.vip?(user_id) ? "vip" : "std" }
|
100
|
+
},
|
101
|
+
# Allow 1000 jobs/hour to be processed for VIPs and 10/day for all others
|
102
|
+
:threshold => {
|
103
|
+
:limit => ->(user_id) { User.vip?(user_id) ? 1_000 : 10 },
|
104
|
+
:period => ->(user_id) { User.vip?(user_id) ? 1.hour : 1.day },
|
105
|
+
:key_suffix => ->(user_id) { User.vip?(user_id) ? "vip" : "std" }
|
106
|
+
})
|
107
|
+
|
108
|
+
def perform(user_id)
|
109
|
+
# ...
|
110
|
+
end
|
111
|
+
end
|
112
|
+
```
|
113
|
+
|
114
|
+
**NB** Don't forget to specify `:key_suffix` and make it return different values
|
115
|
+
if you are using dynamic limit/period options. Otherwise you risk getting into
|
116
|
+
some trouble.
|
117
|
+
|
88
118
|
|
89
119
|
## Supported Ruby Versions
|
90
120
|
|
@@ -42,9 +42,12 @@ module Sidekiq
|
|
42
42
|
raise ArgumentError, "Neither :concurrency nor :threshold given"
|
43
43
|
end
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
|
45
|
+
# @return [Boolean] whenever strategy has dynamic config
|
46
|
+
def dynamic?
|
47
|
+
return true if @concurrency && @concurrency.dynamic?
|
48
|
+
return true if @threshold && @threshold.dynamic?
|
49
|
+
|
50
|
+
false
|
48
51
|
end
|
49
52
|
|
50
53
|
# @return [Boolean] whenever job is throttled or not.
|
@@ -17,31 +17,34 @@ module Sidekiq
|
|
17
17
|
SCRIPT = Script.new File.read "#{__dir__}/concurrency.lua"
|
18
18
|
private_constant :SCRIPT
|
19
19
|
|
20
|
-
# @!attribute [r] limit
|
21
|
-
# @return [Integer] Amount of allwoed concurrent job processors
|
22
|
-
attr_reader :limit
|
23
|
-
|
24
20
|
# @param [#to_s] strategy_key
|
25
21
|
# @param [Hash] opts
|
26
|
-
# @option opts [#to_i] :limit Amount of
|
22
|
+
# @option opts [#to_i] :limit Amount of allowed concurrent jobs
|
27
23
|
# processors running for given key
|
28
24
|
# @option opts [#to_i] :ttl (15 minutes) Concurrency lock TTL
|
29
25
|
# in seconds
|
30
26
|
# @option opts :key_suffix Proc for dynamic key suffix.
|
31
27
|
def initialize(strategy_key, opts)
|
32
|
-
@base_key
|
33
|
-
@limit
|
34
|
-
@ttl
|
28
|
+
@base_key = "#{strategy_key}:concurrency".freeze
|
29
|
+
@limit = opts.fetch(:limit)
|
30
|
+
@ttl = opts.fetch(:ttl, 900).to_i
|
35
31
|
@key_suffix = opts[:key_suffix]
|
36
32
|
end
|
37
33
|
|
38
|
-
|
39
|
-
|
34
|
+
# @return [Integer] Amount of allowed concurrent job processors
|
35
|
+
def limit(job_args = nil)
|
36
|
+
return @limit.to_i unless @limit.respond_to? :call
|
37
|
+
@limit.call(*job_args).to_i
|
38
|
+
end
|
39
|
+
|
40
|
+
# @return [Boolean] Whenever strategy has dynamic config
|
41
|
+
def dynamic?
|
42
|
+
@key_suffix || @limit.respond_to?(:call)
|
40
43
|
end
|
41
44
|
|
42
45
|
# @return [Boolean] whenever job is throttled or not
|
43
46
|
def throttled?(jid, *job_args)
|
44
|
-
1 == SCRIPT.eval([key(job_args)], [
|
47
|
+
1 == SCRIPT.eval([key(job_args)], [limit(job_args), @ttl, jid.to_s])
|
45
48
|
end
|
46
49
|
|
47
50
|
# @return [Integer] Current count of jobs
|
@@ -13,7 +13,7 @@ module Sidekiq
|
|
13
13
|
# Logic behind the scene can be described in following pseudo code:
|
14
14
|
#
|
15
15
|
# def exceeded?
|
16
|
-
#
|
16
|
+
# limit <= LLEN(@key) && NOW - LINDEX(@key, -1) < @period
|
17
17
|
# end
|
18
18
|
#
|
19
19
|
# def increase!
|
@@ -29,32 +29,40 @@ module Sidekiq
|
|
29
29
|
SCRIPT = Script.new File.read "#{__dir__}/threshold.lua"
|
30
30
|
private_constant :SCRIPT
|
31
31
|
|
32
|
-
# @!attribute [r] limit
|
33
|
-
# @return [Integer] Amount of jobs allowed per period
|
34
|
-
attr_reader :limit
|
35
|
-
|
36
|
-
# @!attribute [r] period
|
37
|
-
# @return [Float] Period in seconds
|
38
|
-
attr_reader :period
|
39
|
-
|
40
32
|
# @param [#to_s] strategy_key
|
41
33
|
# @param [Hash] opts
|
42
34
|
# @option opts [#to_i] :limit Amount of jobs allowed per period
|
43
35
|
# @option opts [#to_f] :period Period in seconds
|
44
36
|
def initialize(strategy_key, opts)
|
45
|
-
@base_key
|
46
|
-
@limit
|
47
|
-
@period
|
37
|
+
@base_key = "#{strategy_key}:threshold".freeze
|
38
|
+
@limit = opts.fetch(:limit)
|
39
|
+
@period = opts.fetch(:period)
|
48
40
|
@key_suffix = opts[:key_suffix]
|
49
41
|
end
|
50
42
|
|
51
|
-
|
52
|
-
|
43
|
+
# @return [Integer] Amount of jobs allowed per period
|
44
|
+
def limit(job_args = nil)
|
45
|
+
return @limit.to_i unless @limit.respond_to? :call
|
46
|
+
@limit.call(*job_args).to_i
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [Float] Period in seconds
|
50
|
+
def period(job_args = nil)
|
51
|
+
return @period.to_f unless @period.respond_to? :call
|
52
|
+
@period.call(*job_args).to_f
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [Boolean] Whenever strategy has dynamic config
|
56
|
+
def dynamic?
|
57
|
+
@key_suffix || @limit.respond_to?(:call) || @period.respond_to?(:call)
|
53
58
|
end
|
54
59
|
|
55
60
|
# @return [Boolean] whenever job is throttled or not
|
56
61
|
def throttled?(*job_args)
|
57
|
-
|
62
|
+
key = key(job_args)
|
63
|
+
limit = limit(job_args)
|
64
|
+
period = period(job_args)
|
65
|
+
1 == SCRIPT.eval([key], [limit, period, Time.now.to_f])
|
58
66
|
end
|
59
67
|
|
60
68
|
# @return [Integer] Current count of jobs
|
@@ -14,8 +14,8 @@ module Sidekiq
|
|
14
14
|
|
15
15
|
# @param [Strategy::Concurrency, Strategy::Threshold] strategy
|
16
16
|
def initialize(strategy)
|
17
|
-
if strategy && strategy.
|
18
|
-
raise ArgumentError, "Can't handle
|
17
|
+
if strategy && strategy.dynamic?
|
18
|
+
raise ArgumentError, "Can't handle dynamic strategies"
|
19
19
|
end
|
20
20
|
@strategy = strategy
|
21
21
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidekiq-throttled
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexey V Zapparov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-05-
|
11
|
+
date: 2016-05-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sidekiq
|
@@ -56,7 +56,6 @@ files:
|
|
56
56
|
- LICENSE.md
|
57
57
|
- README.md
|
58
58
|
- Rakefile
|
59
|
-
- bin/setup
|
60
59
|
- gemfiles/sidekiq_3.x.gemfile
|
61
60
|
- gemfiles/sidekiq_4.0.gemfile
|
62
61
|
- gemfiles/sidekiq_4.1.gemfile
|