sidekiq-throttled 0.3.2 → 0.4.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
  SHA1:
3
- metadata.gz: 89651103d182029649562546de86fa491ac2fd78
4
- data.tar.gz: b5d7b35e556a536c6d721d1332d66605120f5918
3
+ metadata.gz: b39d91ca9d489440aa46f943c0bfb4dafd977621
4
+ data.tar.gz: 754e0213ad9081a626f50d7711a4d8de7076e15e
5
5
  SHA512:
6
- metadata.gz: a3a1c17f1b72f7e9afc361265519bf067b6460474b9396d19369c06c4d6a509e973500d5b9016b97ad948f753ab24ce18ff573f1d97d11f2649ae4c1471a0a72
7
- data.tar.gz: 27e73f96f33a6c3acaaa0eb7b8ae25f6c5672cb8d57763df7e9a0cab32bd679184eaad46623b23f9e6de158a6ec0d9ace231e8f7b377d4e6dee0eed6ca2b29af
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
 
@@ -80,7 +80,7 @@ module Sidekiq
80
80
  def each_with_static_keys
81
81
  return to_enum(__method__) unless block_given?
82
82
  @strategies.each do |name, strategy|
83
- yield(name, strategy) unless strategy.dynamic_keys?
83
+ yield(name, strategy) unless strategy.dynamic?
84
84
  end
85
85
  end
86
86
  end
@@ -42,9 +42,12 @@ module Sidekiq
42
42
  raise ArgumentError, "Neither :concurrency nor :threshold given"
43
43
  end
44
44
 
45
- def dynamic_keys?
46
- (@concurrency && @concurrency.dynamic_keys?) ||
47
- (@threshold && @threshold.dynamic_keys?)
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 allwoed concurrent jobs
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 = "#{strategy_key}:concurrency".freeze
33
- @limit = opts.fetch(:limit).to_i
34
- @ttl = opts.fetch(:ttl, 900).to_i
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
- def dynamic_keys?
39
- @key_suffix
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)], [@limit, @ttl, jid.to_s])
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
- # @limit <= LLEN(@key) && NOW - LINDEX(@key, -1) < @period
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 = "#{strategy_key}:threshold".freeze
46
- @limit = opts.fetch(:limit).to_i
47
- @period = opts.fetch(:period).to_f
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
- def dynamic_keys?
52
- @key_suffix
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
- 1 == SCRIPT.eval([key(job_args)], [@limit, @period, Time.now.to_f])
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
@@ -3,6 +3,6 @@
3
3
  module Sidekiq
4
4
  module Throttled
5
5
  # Gem version
6
- VERSION = "0.3.2".freeze
6
+ VERSION = "0.4.0".freeze
7
7
  end
8
8
  end
@@ -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.dynamic_keys?
18
- raise ArgumentError, "Can't handle strategies with dynamic keys"
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.3.2
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-16 00:00:00.000000000 Z
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
data/bin/setup DELETED
@@ -1,6 +0,0 @@
1
- #!/bin/bash
2
-
3
- set -euo pipefail
4
- IFS=$'\n\t'
5
-
6
- bundle install