sidekiq-throttled 0.7.3 → 0.8.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: 84ceb88578f276b9161f1efa7428e46204da69e7
4
- data.tar.gz: f57a36074d1d25b43125735f1a7fc8249d130533
3
+ metadata.gz: 3e18c53412711982bb7d620c5300d30d89cf1668
4
+ data.tar.gz: abe45ca2b495ee939a8ce11437b9e1fc48664242
5
5
  SHA512:
6
- metadata.gz: f1f1e6086b2d493361a1413abecccdfaef578660f72fd6d46f41dc636fb143039cb54968eec7e497a12a43a70f6f1b74d78d573497f9d6141b1d390ee14677e7
7
- data.tar.gz: b2bbc09d00d09c49ad5653d4eec477fb05049ac2423a3637cfdc5aae80d11e3808fd081fa9144757ff3f392ed45618f958e50ed0d4e264f844d6dd7960012f57
6
+ metadata.gz: e8d86da7c4b388b3b235caff8a887e342cae176d42398ef4033d946532cb6bd4568080db5b1afca15b6f6efe4984dd124229219c73524cb5bfe58ee813461fcb
7
+ data.tar.gz: 83e7c860e3b17b7ec8b4295ea6ddf5d6c9e8f9e984c4fa367d9d803cf2b7403e0bbafc0772df7b679e3e7ad0edfb47729646691eb913b10ff834c424aad97253
data/.rubocop.yml CHANGED
@@ -6,6 +6,34 @@ AllCops:
6
6
  DisplayCopNames: true
7
7
  TargetRubyVersion: 2.4
8
8
 
9
+ ## Layout ######################################################################
10
+
11
+ Layout/AlignHash:
12
+ EnforcedHashRocketStyle: table
13
+
14
+ Layout/AlignParameters:
15
+ EnforcedStyle: with_fixed_indentation
16
+
17
+ Layout/IndentArray:
18
+ EnforcedStyle: consistent
19
+
20
+ Layout/IndentHash:
21
+ EnforcedStyle: consistent
22
+
23
+ Layout/MultilineMethodCallIndentation:
24
+ EnforcedStyle: indented
25
+
26
+ Layout/SpaceInLambdaLiteral:
27
+ EnforcedStyle: require_space
28
+
29
+ ## Layout ######################################################################
30
+
31
+ # Adds useless noise. I would prefer it to enforce blind rescues instead of
32
+ # rescue from StandardError. To me blind rescue is as natural as implicit
33
+ # return.
34
+ Lint/RescueWithoutErrorClass:
35
+ Enabled: false
36
+
9
37
  ## Metrics #####################################################################
10
38
 
11
39
  Metrics/BlockLength:
@@ -15,12 +43,6 @@ Metrics/BlockLength:
15
43
 
16
44
  ## Styles ######################################################################
17
45
 
18
- Style/AlignHash:
19
- EnforcedHashRocketStyle: table
20
-
21
- Style/AlignParameters:
22
- EnforcedStyle: with_fixed_indentation
23
-
24
46
  Style/BracesAroundHashParameters:
25
47
  Enabled: false
26
48
 
@@ -33,21 +55,12 @@ Style/Encoding:
33
55
  Style/HashSyntax:
34
56
  EnforcedStyle: hash_rockets
35
57
 
36
- Style/IndentArray:
37
- EnforcedStyle: consistent
38
-
39
- Style/IndentHash:
40
- EnforcedStyle: consistent
41
-
42
58
  # Follow your heart where it makes sense to use lambda or lambda literal.
43
59
  # Enforcing it makes some pieces of code look REALLY terrible, e.g. in
44
60
  # case of empty (noop) lambdas: `lambda { |_| }`.
45
61
  Style/Lambda:
46
62
  Enabled: false
47
63
 
48
- Style/MultilineMethodCallIndentation:
49
- EnforcedStyle: indented
50
-
51
64
  # Enabling this cop makes Guardfile (which is full of pathname regexps)
52
65
  # look absolutley style-inconsistent and terrible. In any case, this should
53
66
  # be on developer's choice whenever to use `%r` or not. Just like we don't
@@ -55,8 +68,9 @@ Style/MultilineMethodCallIndentation:
55
68
  Style/RegexpLiteral:
56
69
  Enabled: false
57
70
 
58
- Style/SpaceInLambdaLiteral:
59
- EnforcedStyle: require_space
60
-
61
71
  Style/StringLiterals:
62
72
  EnforcedStyle: double_quotes
73
+
74
+ # I prefer Yoda style instead, but there's no such enforcement style.
75
+ Style/YodaCondition:
76
+ Enabled: false
data/Appraisals CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  appraise "sidekiq-4.0" do
2
4
  gem "sidekiq", "~> 4.0.0"
3
5
  end
data/CHANGES.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## 0.8.0 (2017-10-11)
2
+
3
+ * Refactor concurrency throttling internals to use sorted sets in order to avoid
4
+ starvation in case when finalize! was not called (OOM / redis issues).
5
+ ([@ixti])
6
+
7
+
1
8
  ## 0.7.3 (2017-06-26)
2
9
 
3
10
  * [#34](https://github.com/sensortower/sidekiq-throttled/issues/34)
data/Gemfile CHANGED
@@ -6,7 +6,7 @@ gem "appraisal"
6
6
  gem "rake"
7
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"
11
11
 
12
12
  group :development do
data/Rakefile CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "bundler/gem_tasks"
3
4
 
4
5
  require "rspec/core/rake_task"
@@ -20,7 +21,7 @@ namespace :rubocop do
20
21
  end
21
22
  end
22
23
 
23
- default_suite = ENV["CI"] ? :spec : %i(spec rubocop)
24
+ default_suite = ENV["CI"] ? :spec : %i[spec rubocop]
24
25
  named_suites = { "rubocop" => :rubocop, "rspec" => :spec }
25
26
 
26
27
  task :default => named_suites.fetch(ENV["SUITE"], default_suite)
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # 3rd party
3
4
  require "sidekiq"
4
5
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Sidekiq
3
4
  module Throttled
4
5
  # Generic class for Sidekiq::Throttled errors
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # internal
3
4
  require "sidekiq/throttled/registry"
4
5
 
@@ -58,7 +58,7 @@ module Sidekiq
58
58
  end
59
59
 
60
60
  @communicator.ready do
61
- @paused_queues.replace paused_queues.map { |q| QueueName.expand q }
61
+ @paused_queues.replace(paused_queues.map { |q| QueueName.expand q })
62
62
  end
63
63
  end
64
64
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # internal
3
4
  require "sidekiq/throttled/strategy"
4
5
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # internal
3
4
  require "sidekiq/throttled/errors"
4
5
  require "sidekiq/throttled/strategy/concurrency"
@@ -2,12 +2,15 @@ local key = KEYS[1]
2
2
  local jid = ARGV[1]
3
3
  local lmt = tonumber(ARGV[2])
4
4
  local ttl = tonumber(ARGV[3])
5
+ local now = tonumber(ARGV[4])
5
6
 
6
- if lmt <= redis.call("SCARD", key) and 0 == redis.call("SISMEMBER", key, jid) then
7
+ redis.call("ZREMRANGEBYSCORE", key, "-inf", "(" .. now)
8
+
9
+ if lmt <= redis.call("ZCARD", key) and not redis.call("ZSCORE", key, jid) then
7
10
  return 1
8
11
  end
9
12
 
10
- redis.call("SADD", key, jid)
13
+ redis.call("ZADD", key, now + ttl, jid)
11
14
  redis.call("EXPIRE", key, ttl)
12
15
 
13
16
  return 0
@@ -28,7 +28,7 @@ module Sidekiq
28
28
  # @param [#to_i] ttl Concurrency lock TTL in seconds.
29
29
  # @param [Proc] key_suffix Dynamic key suffix generator.
30
30
  def initialize(strategy_key, limit:, ttl: 900, key_suffix: nil)
31
- @base_key = "#{strategy_key}:concurrency"
31
+ @base_key = "#{strategy_key}:concurrency.v2"
32
32
  @limit = limit
33
33
  @ttl = ttl.to_i
34
34
  @key_suffix = key_suffix
@@ -44,14 +44,14 @@ module Sidekiq
44
44
  return false unless (job_limit = limit(job_args))
45
45
 
46
46
  keys = [key(job_args)]
47
- args = [jid.to_s, job_limit, @ttl]
47
+ args = [jid.to_s, job_limit, @ttl, Time.now.to_f]
48
48
 
49
49
  1 == SCRIPT.eval(keys, args)
50
50
  end
51
51
 
52
52
  # @return [Integer] Current count of jobs
53
53
  def count(*job_args)
54
- Sidekiq.redis { |conn| conn.scard(key(job_args)) }.to_i
54
+ Sidekiq.redis { |conn| conn.zcard(key(job_args)) }.to_i
55
55
  end
56
56
 
57
57
  # Resets count of jobs
@@ -63,7 +63,7 @@ module Sidekiq
63
63
  # Remove jid from the pool of jobs in progress
64
64
  # @return [void]
65
65
  def finalize!(jid, *job_args)
66
- Sidekiq.redis { |conn| conn.srem(key(job_args), jid.to_s) }
66
+ Sidekiq.redis { |conn| conn.zrem(key(job_args), jid.to_s) }
67
67
  end
68
68
  end
69
69
  end
@@ -41,7 +41,7 @@ module Sidekiq
41
41
  # Loads script to redis
42
42
  # @return [void]
43
43
  def bootstrap!
44
- Sidekiq.redis do |conn|
44
+ namespaceless_redis do |conn|
45
45
  digest = conn.script(LOAD, @source)
46
46
 
47
47
  # XXX: this may happen **ONLY** if script digesting will be
@@ -76,6 +76,19 @@ module Sidekiq
76
76
  def self.read(file)
77
77
  new File.read file
78
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
79
92
  end
80
93
  end
81
94
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "sidekiq/throttled/registry"
3
4
 
4
5
  RSpec.configure do |config|
@@ -3,6 +3,6 @@
3
3
  module Sidekiq
4
4
  module Throttled
5
5
  # Gem version
6
- VERSION = "0.7.3"
6
+ VERSION = "0.8.0"
7
7
  end
8
8
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Sidekiq
3
4
  module Throttled
4
5
  module Web
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # internal
3
4
  require "sidekiq/throttled/registry"
4
5
 
@@ -1,4 +1,3 @@
1
- # coding: utf-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  lib = File.expand_path("../lib", __FILE__)
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.7.3
4
+ version: 0.8.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: 2017-06-26 00:00:00.000000000 Z
11
+ date: 2017-10-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sidekiq
@@ -113,7 +113,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
113
  version: '0'
114
114
  requirements: []
115
115
  rubyforge_project:
116
- rubygems_version: 2.6.12
116
+ rubygems_version: 2.6.13
117
117
  signing_key:
118
118
  specification_version: 4
119
119
  summary: Concurrency and threshold throttling for Sidekiq.