sidekiq-throttled 0.8.1 → 0.8.2

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
- SHA1:
3
- metadata.gz: 8ef8cce2c35072fd109e89066e293074fb125828
4
- data.tar.gz: 575ea548b4594445fd8b2532896bac87149e96ef
2
+ SHA256:
3
+ metadata.gz: 719506019ae06cb2b89b220681ca460b6446965aefd2268c3546c667e5f50fb5
4
+ data.tar.gz: 4e4a2f78b9bb978a20d4971ee9c7a78386405639d3c2a8a194d47c5e55d9ce32
5
5
  SHA512:
6
- metadata.gz: 4f5b3b2b3023f776b247e07db7959ad691990d6dbddf26c662e101b95868440dea2c3f2c81f9ed139b5b471bfdc259b6a52649957f5bd809ec508b2f53fc7488
7
- data.tar.gz: 5a898501386292385f3399ce572ea47110766e72c38dbf9ab5f57f23bca155c66c2e32cdb0c4b9adf31155b48382e96ca4a071294325cec3fc3beaa66ae9178b
6
+ metadata.gz: a0d220ca8d744ff3e211877b3f726305ed66e93a9045c402b569162e2d9d324ba6f00cbddf1f271cd33bba8ab7602bcead13e61f980576de9ec8d801e8814d29
7
+ data.tar.gz: 87b134e30aef111a955df66e48fec23df2152bb90e61063ef9737daf858d5525b5c70648519048d143c4399c47111ade2e84d7212ada43bc203cf2430ae8ad60
data/.gitignore CHANGED
@@ -1,6 +1,7 @@
1
1
  /.bundle/
2
2
  /.yardoc
3
3
  /Gemfile.lock
4
+ /gemfiles/.bundle
4
5
  /gemfiles/*.gemfile.lock
5
6
  /_yardoc/
6
7
  /coverage/
@@ -51,3 +51,4 @@ gemfile:
51
51
  - gemfiles/sidekiq_4.1.gemfile
52
52
  - gemfiles/sidekiq_4.2.gemfile
53
53
  - gemfiles/sidekiq_5.0.gemfile
54
+ - gemfiles/sidekiq_5.1.gemfile
data/Appraisals CHANGED
@@ -15,3 +15,7 @@ end
15
15
  appraise "sidekiq-5.0" do
16
16
  gem "sidekiq", "~> 5.0.0"
17
17
  end
18
+
19
+ appraise "sidekiq-5.1" do
20
+ gem "sidekiq", "~> 5.1.0"
21
+ end
data/CHANGES.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## 0.8.2 (2018-02-14)
2
+
3
+ * Extract redis LUA scripts stored procedures runner to redis-prescription gem.
4
+ ([@ixti])
5
+
6
+ * Switch to Concurrent.monotonic_time to expire elements of ExpirableList.
7
+ ([@ixti])
8
+
9
+
1
10
  ## 0.8.1 (2017-11-02)
2
11
 
3
12
  * Preload job class constant prior trying to get it's throttling strategy.
data/README.md CHANGED
@@ -181,6 +181,7 @@ This library aims to support work with following [Sidekiq][sidekiq] versions:
181
181
  * Sidekiq 4.1.x
182
182
  * Sidekiq 4.2.x
183
183
  * Sidekiq 5.0.x
184
+ * Sidekiq 5.1.x
184
185
 
185
186
 
186
187
  ## Contributing
@@ -197,10 +198,10 @@ This library aims to support work with following [Sidekiq][sidekiq] versions:
197
198
 
198
199
  ```
199
200
  bundle update
200
- appraisal install # install dependencies for all gemfiles
201
- appraisal update # update dependencies for all gemfiles
202
- appraisal rspec # run rspec against each gemfile
203
- bundle exec rubocop # run static code analysis
201
+ bundle exec appraisal install # install dependencies for all gemfiles
202
+ bundle exec appraisal update # update dependencies for all gemfiles
203
+ bundle exec appraisal rspec # run rspec against each gemfile
204
+ bundle exec rubocop # run static code analysis
204
205
  ```
205
206
 
206
207
  Don't forget to run `appraisal update` after any changes to `Gemfile`.
@@ -4,21 +4,21 @@ source "https://rubygems.org"
4
4
 
5
5
  gem "appraisal"
6
6
  gem "rake"
7
- gem "redis-namespace", :require => false
7
+ gem "redis-namespace", require: false
8
8
  gem "rspec"
9
- gem "rubocop", "~> 0.47.0", :require => false
9
+ gem "rubocop", "~> 0.50.0", require: false
10
10
  gem "sidekiq", "~> 4.0.0"
11
11
 
12
12
  group :development do
13
13
  gem "byebug"
14
- gem "guard", :require => false
15
- gem "guard-rspec", :require => false
16
- gem "guard-rubocop", :require => false
14
+ gem "guard", require: false
15
+ gem "guard-rspec", require: false
16
+ gem "guard-rubocop", require: false
17
17
  end
18
18
 
19
19
  group :test do
20
20
  gem "capybara"
21
- gem "coveralls", :require => false
21
+ gem "coveralls", require: false
22
22
  gem "poltergeist"
23
23
  gem "rack-test"
24
24
  gem "simplecov", ">= 0.9"
@@ -26,4 +26,4 @@ group :test do
26
26
  gem "timecop"
27
27
  end
28
28
 
29
- gemspec :path => "../"
29
+ gemspec path: "../"
@@ -4,21 +4,21 @@ source "https://rubygems.org"
4
4
 
5
5
  gem "appraisal"
6
6
  gem "rake"
7
- gem "redis-namespace", :require => false
7
+ gem "redis-namespace", require: false
8
8
  gem "rspec"
9
- gem "rubocop", "~> 0.47.0", :require => false
9
+ gem "rubocop", "~> 0.50.0", require: false
10
10
  gem "sidekiq", "~> 4.1.0"
11
11
 
12
12
  group :development do
13
13
  gem "byebug"
14
- gem "guard", :require => false
15
- gem "guard-rspec", :require => false
16
- gem "guard-rubocop", :require => false
14
+ gem "guard", require: false
15
+ gem "guard-rspec", require: false
16
+ gem "guard-rubocop", require: false
17
17
  end
18
18
 
19
19
  group :test do
20
20
  gem "capybara"
21
- gem "coveralls", :require => false
21
+ gem "coveralls", require: false
22
22
  gem "poltergeist"
23
23
  gem "rack-test"
24
24
  gem "simplecov", ">= 0.9"
@@ -26,4 +26,4 @@ group :test do
26
26
  gem "timecop"
27
27
  end
28
28
 
29
- gemspec :path => "../"
29
+ gemspec path: "../"
@@ -4,21 +4,21 @@ source "https://rubygems.org"
4
4
 
5
5
  gem "appraisal"
6
6
  gem "rake"
7
- gem "redis-namespace", :require => false
7
+ gem "redis-namespace", require: false
8
8
  gem "rspec"
9
- gem "rubocop", "~> 0.47.0", :require => false
9
+ gem "rubocop", "~> 0.50.0", require: false
10
10
  gem "sidekiq", "~> 4.2.0"
11
11
 
12
12
  group :development do
13
13
  gem "byebug"
14
- gem "guard", :require => false
15
- gem "guard-rspec", :require => false
16
- gem "guard-rubocop", :require => false
14
+ gem "guard", require: false
15
+ gem "guard-rspec", require: false
16
+ gem "guard-rubocop", require: false
17
17
  end
18
18
 
19
19
  group :test do
20
20
  gem "capybara"
21
- gem "coveralls", :require => false
21
+ gem "coveralls", require: false
22
22
  gem "poltergeist"
23
23
  gem "rack-test"
24
24
  gem "simplecov", ">= 0.9"
@@ -26,4 +26,4 @@ group :test do
26
26
  gem "timecop"
27
27
  end
28
28
 
29
- gemspec :path => "../"
29
+ gemspec path: "../"
@@ -4,21 +4,21 @@ source "https://rubygems.org"
4
4
 
5
5
  gem "appraisal"
6
6
  gem "rake"
7
- gem "redis-namespace", :require => false
7
+ gem "redis-namespace", require: false
8
8
  gem "rspec"
9
- gem "rubocop", "~> 0.47.0", :require => false
9
+ gem "rubocop", "~> 0.50.0", require: false
10
10
  gem "sidekiq", "~> 5.0.0"
11
11
 
12
12
  group :development do
13
13
  gem "byebug"
14
- gem "guard", :require => false
15
- gem "guard-rspec", :require => false
16
- gem "guard-rubocop", :require => false
14
+ gem "guard", require: false
15
+ gem "guard-rspec", require: false
16
+ gem "guard-rubocop", require: false
17
17
  end
18
18
 
19
19
  group :test do
20
20
  gem "capybara"
21
- gem "coveralls", :require => false
21
+ gem "coveralls", require: false
22
22
  gem "poltergeist"
23
23
  gem "rack-test"
24
24
  gem "simplecov", ">= 0.9"
@@ -26,4 +26,4 @@ group :test do
26
26
  gem "timecop"
27
27
  end
28
28
 
29
- gemspec :path => "../"
29
+ gemspec path: "../"
@@ -0,0 +1,29 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal"
6
+ gem "rake"
7
+ gem "redis-namespace", require: false
8
+ gem "rspec"
9
+ gem "rubocop", "~> 0.50.0", require: false
10
+ gem "sidekiq", "~> 5.1.0"
11
+
12
+ group :development do
13
+ gem "byebug"
14
+ gem "guard", require: false
15
+ gem "guard-rspec", require: false
16
+ gem "guard-rubocop", require: false
17
+ end
18
+
19
+ group :test do
20
+ gem "capybara"
21
+ gem "coveralls", require: false
22
+ gem "poltergeist"
23
+ gem "rack-test"
24
+ gem "simplecov", ">= 0.9"
25
+ gem "sinatra", "~> 1.4", ">= 1.4.6"
26
+ gem "timecop"
27
+ end
28
+
29
+ gemspec path: "../"
@@ -2,6 +2,8 @@
2
2
 
3
3
  require "monitor"
4
4
 
5
+ require "concurrent/utility/monotonic_time"
6
+
5
7
  module Sidekiq
6
8
  module Throttled
7
9
  # List that tracks when elements were added and enumerates over those not
@@ -10,18 +12,22 @@ module Sidekiq
10
12
  # ## Implementation
11
13
  #
12
14
  # Internally list holds an array of arrays. Thus ecah element is a tuple of
13
- # timestamp (when element was added) and element itself:
15
+ # monotonic timestamp (when element was added) and element itself:
14
16
  #
15
17
  # [
16
- # [ 1234567890.12345, "default" ],
17
- # [ 1234567890.34567, "urgent" ],
18
- # [ 1234579621.56789, "urgent" ],
18
+ # [ 123456.7890, "default" ],
19
+ # [ 123456.7891, "urgent" ],
20
+ # [ 123457.9621, "urgent" ],
19
21
  # ...
20
22
  # ]
21
23
  #
22
24
  # It does not deduplicates elements. Eviction happens only upon elements
23
25
  # retrieval (see {#each}).
24
26
  #
27
+ # @see http://ruby-concurrency.github.io/concurrent-ruby/Concurrent.html#monotonic_time-class_method
28
+ # @see https://ruby-doc.org/core/Process.html#method-c-clock_gettime
29
+ # @see https://linux.die.net/man/3/clock_gettime
30
+ #
25
31
  # @private
26
32
  class ExpirableList
27
33
  include Enumerable
@@ -38,7 +44,7 @@ module Sidekiq
38
44
  # @params element [Object]
39
45
  # @return [ExpirableList] self
40
46
  def <<(element)
41
- @mon.synchronize { @arr << [Time.now.to_f, element] }
47
+ @mon.synchronize { @arr << [Concurrent.monotonic_time, element] }
42
48
  self
43
49
  end
44
50
 
@@ -52,7 +58,7 @@ module Sidekiq
52
58
  return to_enum __method__ unless block_given?
53
59
 
54
60
  @mon.synchronize do
55
- horizon = Time.now.to_f - @ttl
61
+ horizon = Concurrent.monotonic_time - @ttl
56
62
 
57
63
  # drop all elements older than horizon
58
64
  @arr.shift while @arr[0] && @arr[0][0] < horizon
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "redis/prescription"
4
+
3
5
  require "sidekiq/throttled/strategy/base"
4
- require "sidekiq/throttled/strategy/script"
5
6
 
6
7
  module Sidekiq
7
8
  module Throttled
@@ -19,7 +20,7 @@ module Sidekiq
19
20
  # PUSH(@key, @jid)
20
21
  # return 0
21
22
  # end
22
- SCRIPT = Script.read "#{__dir__}/concurrency.lua"
23
+ SCRIPT = Redis::Prescription.read "#{__dir__}/concurrency.lua"
23
24
  private_constant :SCRIPT
24
25
 
25
26
  # @param [#to_s] strategy_key
@@ -43,10 +44,12 @@ module Sidekiq
43
44
  def throttled?(jid, *job_args)
44
45
  return false unless (job_limit = limit(job_args))
45
46
 
46
- keys = [key(job_args)]
47
- args = [jid.to_s, job_limit, @ttl, Time.now.to_f]
47
+ kwargs = {
48
+ :keys => [key(job_args)],
49
+ :argv => [jid.to_s, job_limit, @ttl, Time.now.to_f]
50
+ }
48
51
 
49
- 1 == SCRIPT.eval(keys, args)
52
+ Sidekiq.redis { |redis| 1 == SCRIPT.eval(redis, kwargs) }
50
53
  end
51
54
 
52
55
  # @return [Integer] Current count of jobs
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "redis/prescription"
4
+
3
5
  require "sidekiq/throttled/strategy/base"
4
- require "sidekiq/throttled/strategy/script"
5
6
 
6
7
  module Sidekiq
7
8
  module Throttled
@@ -29,7 +30,7 @@ module Sidekiq
29
30
  #
30
31
  # increase!
31
32
  # return 0
32
- SCRIPT = Script.read "#{__dir__}/threshold.lua"
33
+ SCRIPT = Redis::Prescription.read "#{__dir__}/threshold.lua"
33
34
  private_constant :SCRIPT
34
35
 
35
36
  # @param [#to_s] strategy_key
@@ -59,10 +60,12 @@ module Sidekiq
59
60
  def throttled?(*job_args)
60
61
  return false unless (job_limit = limit(job_args))
61
62
 
62
- keys = [key(job_args)]
63
- args = [job_limit, period(job_args), Time.now.to_f]
63
+ kwargs = {
64
+ :keys => [key(job_args)],
65
+ :argv => [job_limit, period(job_args), Time.now.to_f]
66
+ }
64
67
 
65
- 1 == SCRIPT.eval(keys, args)
68
+ Sidekiq.redis { |redis| 1 == SCRIPT.eval(redis, kwargs) }
66
69
  end
67
70
 
68
71
  # @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.8.1"
6
+ VERSION = "0.8.2"
7
7
  end
8
8
  end
@@ -25,6 +25,7 @@ Gem::Specification.new do |spec|
25
25
  spec.require_paths = ["lib"]
26
26
 
27
27
  spec.add_runtime_dependency "sidekiq"
28
+ spec.add_runtime_dependency "redis-prescription"
28
29
 
29
30
  spec.add_development_dependency "bundler", "~> 1.10"
30
31
  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.8.1
4
+ version: 0.8.2
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: 2017-11-02 00:00:00.000000000 Z
11
+ date: 2018-02-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sidekiq
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: redis-prescription
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -63,6 +77,7 @@ files:
63
77
  - gemfiles/sidekiq_4.1.gemfile
64
78
  - gemfiles/sidekiq_4.2.gemfile
65
79
  - gemfiles/sidekiq_5.0.gemfile
80
+ - gemfiles/sidekiq_5.1.gemfile
66
81
  - lib/sidekiq/throttled.rb
67
82
  - lib/sidekiq/throttled/communicator.rb
68
83
  - lib/sidekiq/throttled/communicator/callbacks.rb
@@ -80,7 +95,6 @@ files:
80
95
  - lib/sidekiq/throttled/strategy/base.rb
81
96
  - lib/sidekiq/throttled/strategy/concurrency.lua
82
97
  - lib/sidekiq/throttled/strategy/concurrency.rb
83
- - lib/sidekiq/throttled/strategy/script.rb
84
98
  - lib/sidekiq/throttled/strategy/threshold.lua
85
99
  - lib/sidekiq/throttled/strategy/threshold.rb
86
100
  - lib/sidekiq/throttled/testing.rb
@@ -113,7 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
127
  version: '0'
114
128
  requirements: []
115
129
  rubyforge_project:
116
- rubygems_version: 2.6.13
130
+ rubygems_version: 2.7.3
117
131
  signing_key:
118
132
  specification_version: 4
119
133
  summary: Concurrency and threshold throttling for Sidekiq.
@@ -1,95 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "digest/sha1"
4
-
5
- require "sidekiq"
6
-
7
- module Sidekiq
8
- module Throttled
9
- class Strategy
10
- # Lua script executor for redis.
11
- #
12
- # Instead of executing script with `EVAL` everytime - loads script once
13
- # and then runs it with `EVALSHA`.
14
- #
15
- # @private
16
- class Script
17
- # Script load command
18
- LOAD = "load"
19
- private_constant :LOAD
20
-
21
- # Redis error fired when script ID is unkown
22
- NOSCRIPT = "NOSCRIPT"
23
- private_constant :NOSCRIPT
24
-
25
- # LUA script source.
26
- # @return [String]
27
- attr_reader :source
28
-
29
- # LUA script SHA1 digest.
30
- # @return [String]
31
- attr_reader :digest
32
-
33
- # @param [#to_s] source Lua script
34
- # @param [Logger] logger
35
- def initialize(source, logger: Sidekiq.logger)
36
- @source = source.to_s.strip.freeze
37
- @digest = Digest::SHA1.hexdigest(@source).freeze
38
- @logger = logger
39
- end
40
-
41
- # Loads script to redis
42
- # @return [void]
43
- def bootstrap!
44
- namespaceless_redis do |conn|
45
- digest = conn.script(LOAD, @source)
46
-
47
- # XXX: this may happen **ONLY** if script digesting will be
48
- # changed in redis, which is not likely gonna happen.
49
- unless @digest == digest
50
- if @logger
51
- @logger.warn "Unexpected script SHA1 digest: " \
52
- "#{digest.inspect} (expected: #{@digest.inspect})"
53
- end
54
-
55
- @digest = digest.freeze
56
- end
57
- end
58
- end
59
-
60
- # Executes script and returns result of execution
61
- # @return Result of script execution
62
- def eval(*args)
63
- Sidekiq.redis do |conn|
64
- begin
65
- conn.evalsha(@digest, *args)
66
- rescue => e
67
- raise unless e.message.include? NOSCRIPT
68
- bootstrap!
69
- conn.evalsha(@digest, *args)
70
- end
71
- end
72
- end
73
-
74
- # Reads given file and returns new {Script} with its contents.
75
- # @return [Script]
76
- def self.read(file)
77
- new File.read file
78
- end
79
-
80
- private
81
-
82
- # Yields real namespace-less redis client.
83
- def namespaceless_redis
84
- Sidekiq.redis do |conn|
85
- if defined?(Redis::Namespace) && conn.is_a?(Redis::Namespace)
86
- conn = conn.redis
87
- end
88
-
89
- yield conn
90
- end
91
- end
92
- end
93
- end
94
- end
95
- end