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 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