sidekiq-throttled 0.7.3 → 0.8.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: 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.