sidekiq-throttled 0.10.0.beta → 0.10.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
  SHA256:
3
- metadata.gz: e6c32e77b9ca7aa1dd0bdad2b74c6fa795f4f660b5d7e7a8f92b16f6b419112e
4
- data.tar.gz: 8d8b4ca63ae59d184846e297fc6281f3b67f282b4f546d1ada0a002e84f65232
3
+ metadata.gz: a204bc340965b64fe16f9b896815c9b3fbf383418b0774871d90c35d4c8fb061
4
+ data.tar.gz: bb2b9681a7caf33d3418ab2f475bc0ab2f6141ed9e6609d55d680815da71c4e6
5
5
  SHA512:
6
- metadata.gz: 24159823a56f6765079ebb27b16b2a2288950a4bab13f628f2d48bd45939400c29d2c640db5af69dd2320e5b973d0a5afeda15cceb457fe90db1b69f8f81fa53
7
- data.tar.gz: 60c65d079962a86fdd02787d1ff2262ace7a31c16a751835038f9d06031f5af8d3d1bb65ec2bfd97ccf542a83cfa97da0ea2a1a70b8993c6793c8bf50fb2ab64
6
+ metadata.gz: '0801102f967a02d3a023b9d8bfe04b8d44280c5f2986182ef4a5cc6e971091afcb3fb1b6c845f382829de071e11d6a3111cb04a21b040b022b61ecac76d5a422'
7
+ data.tar.gz: 243ceeb9a791417edc07a7f697660035e52a61f3db4aefbe93508be5037d1af1932d2b3ad81886ee1b9ef8408e97f1bef8cac03b9a78d8e4c29a2197f9f927f6
@@ -8,7 +8,7 @@ require:
8
8
 
9
9
  AllCops:
10
10
  DisplayCopNames: true
11
- TargetRubyVersion: 2.3
11
+ TargetRubyVersion: 2.4
12
12
  Exclude:
13
13
  - "gemfiles/*"
14
14
 
@@ -9,8 +9,9 @@ cache: bundler
9
9
  before_install:
10
10
  - gem update --system
11
11
  - gem --version
12
- - gem install bundler --no-rdoc --no-ri
12
+ - gem install bundler
13
13
  - bundle --version
14
+ # Install pahantomjs
14
15
  - mkdir travis-phantomjs
15
16
  - wget https://s3.amazonaws.com/travis-phantomjs/phantomjs-2.0.0-ubuntu-12.04.tar.bz2 -O $PWD/travis-phantomjs/phantomjs-2.0.0-ubuntu-12.04.tar.bz2
16
17
  - tar -xvf $PWD/travis-phantomjs/phantomjs-2.0.0-ubuntu-12.04.tar.bz2 -C $PWD/travis-phantomjs
@@ -19,15 +20,15 @@ before_install:
19
20
  install: bundle install --without development
20
21
 
21
22
  rvm:
22
- - 2.3
23
23
  - 2.4
24
24
  - 2.5
25
+ - 2.6
25
26
 
26
27
  matrix:
27
28
  fast_finish: true
28
29
  include:
29
30
  -
30
- rvm: 2.3
31
+ rvm: 2.4
31
32
  env: SUITE="rubocop"
32
33
  gemfile: Gemfile
33
34
 
data/CHANGES.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## 0.10.0 (2019-06-22)
2
+
3
+ * [#60](https://github.com/sensortower/sidekiq-throttled/pull/60)
4
+ Skip throttling check in redis if limit is 0.
5
+ ([@mstruve])
6
+
7
+ * [#58](https://github.com/sensortower/sidekiq-throttled/pull/58)
8
+ Improve documentation bout TTL.
9
+ ([@ziaulrehman40])
10
+
11
+ * Improve reliability of paused queues, by resyncing list of paused queues
12
+ on schedule.
13
+ ([@ixti])
14
+
15
+
1
16
  ## 0.9.0 (2018-09-11)
2
17
 
3
18
  * Add support of Sidekiq 5.2.x
@@ -176,3 +191,5 @@
176
191
  [@palanglung]: https://github.com/palanglung
177
192
  [@azach]: https://github.com/azach
178
193
  [@iporsut]: https://github.com/iporsut
194
+ [@mstruve]: https://github.com/mstruve
195
+ [@ziaulrehman40]: https://github.com/ziaulrehman40
data/README.md CHANGED
@@ -117,6 +117,25 @@ if you are using dynamic limit/period options. Otherwise you risk getting into
117
117
  some trouble.
118
118
 
119
119
 
120
+ ### Concurrency throttling fine-tuning
121
+
122
+ Concurrency throttling is based on distributed locks. Those locks have default
123
+ time to live (TTL) set to 15 minutes. If your job takes more than 15 minutes
124
+ to finish, lock will be released and you might end up with more jobs running
125
+ concurrently than you expect.
126
+
127
+ This is done to avoid deadlocks - when by any reason (e.g. Sidekiq process was
128
+ OOM-killed) cleanup middleware wasn't executed and locks were not released.
129
+
130
+ If your job takes more than 15 minutes to complete, you can tune concurrency
131
+ lock TTL to fit your needs:
132
+
133
+ ``` ruby
134
+ # Set concurrency strategy lock TTL to 1 hour.
135
+ sidekiq_throttle(:concurrency => { :limit => 20, :ttl => 1.hour.to_i })
136
+ ```
137
+
138
+
120
139
  ## Enhanced Queues list
121
140
 
122
141
  This gem provides ability to pause/resume queues from processing by workers.
@@ -155,9 +174,9 @@ end
155
174
  This library aims to support and is [tested against][travis] the following Ruby
156
175
  versions:
157
176
 
158
- * Ruby 2.3.x
159
177
  * Ruby 2.4.x
160
178
  * Ruby 2.5.x
179
+ * Ruby 2.6.x
161
180
 
162
181
  If something doesn't work on one of these versions, it's a bug.
163
182
 
@@ -6,9 +6,11 @@ require "sidekiq"
6
6
  # internal
7
7
  require "sidekiq/throttled/version"
8
8
  require "sidekiq/throttled/communicator"
9
+ require "sidekiq/throttled/configuration"
9
10
  require "sidekiq/throttled/queues_pauser"
10
11
  require "sidekiq/throttled/registry"
11
12
  require "sidekiq/throttled/worker"
13
+ require "sidekiq/throttled/utils"
12
14
 
13
15
  # @see https://github.com/mperham/sidekiq/
14
16
  module Sidekiq
@@ -44,6 +46,13 @@ module Sidekiq
44
46
  private_constant :MUTEX
45
47
 
46
48
  class << self
49
+ include Utils
50
+
51
+ # @return [Configuration]
52
+ def configuration
53
+ @configuration ||= Configuration.new
54
+ end
55
+
47
56
  # Hooks throttler into sidekiq.
48
57
  #
49
58
  # @return [void]
@@ -99,16 +108,6 @@ module Sidekiq
99
108
  @preloaded[job] ||= constantize(job) || true
100
109
  end
101
110
  end
102
-
103
- # Resolve constant from it's name
104
- def constantize(str)
105
- str.sub(/^::/, "").split("::").inject(Object) do |const, name|
106
- const.const_get(name)
107
- end
108
- rescue
109
- Sidekiq.logger.warn { "Failed to constantize: #{str}" }
110
- nil
111
- end
112
111
  end
113
112
  end
114
113
  end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sidekiq
4
+ module Throttled
5
+ # Configuration holder.
6
+ class Configuration
7
+ # Class constructor.
8
+ def initialize
9
+ reset!
10
+ end
11
+
12
+ # Reset configuration to defaults.
13
+ #
14
+ # @return [self]
15
+ def reset!
16
+ @inherit_strategies = false
17
+
18
+ self
19
+ end
20
+
21
+ # Instructs throttler to lookup strategies in parent classes, if there's
22
+ # no own strategy:
23
+ #
24
+ # class Foo
25
+ # include Sidekiq::Worker
26
+ # include Sidekiq::Worker::Throttled
27
+ #
28
+ # sidekiq_throttle :concurrency => { :limit => 42 }
29
+ # end
30
+ #
31
+ # class Bar < Foo
32
+ # end
33
+ #
34
+ # By default in the example above, `Bar` won't have throttling options.
35
+ # Set this flag to `true` to enable this lookup in initializer, after
36
+ # that `Bar` will use `Foo` throttling bucket.
37
+ def inherit_strategies=(value)
38
+ @inherit_strategies = value ? true : false
39
+ end
40
+
41
+ # Whenever throttled workers should inherit parent's strategies or not.
42
+ # Default: `false`.
43
+ #
44
+ # @return [Boolean]
45
+ def inherit_strategies?
46
+ @inherit_strategies
47
+ end
48
+ end
49
+ end
50
+ end
@@ -27,7 +27,7 @@ module Sidekiq
27
27
  # @param [#to_s]
28
28
  # @return [String]
29
29
  def normalize(queue)
30
- queue.to_s.sub(QUEUE_NAME_PREFIX_RE, "")
30
+ -queue.to_s.sub(QUEUE_NAME_PREFIX_RE, "")
31
31
  end
32
32
 
33
33
  # Prepends `queue:` prefix to given `queue` name.
@@ -38,7 +38,7 @@ module Sidekiq
38
38
  # @param [#to_s] queue Queue name
39
39
  # @return [String]
40
40
  def expand(queue)
41
- "queue:#{queue}"
41
+ -"queue:#{queue}"
42
42
  end
43
43
  end
44
44
  end
@@ -65,7 +65,10 @@ module Sidekiq
65
65
  # @private
66
66
  # @return [Array<String>]
67
67
  def filter(queues)
68
- queues - @paused_queues.to_a
68
+ @mutex.synchronize { queues - @paused_queues.to_a }
69
+ rescue => e
70
+ Sidekiq.logger.error { "[#{self.class}] Failed filter queues: #{e}" }
71
+ queues
69
72
  end
70
73
 
71
74
  # Returns list of paused queues.
@@ -2,6 +2,7 @@
2
2
 
3
3
  # internal
4
4
  require "sidekiq/throttled/strategy"
5
+ require "sidekiq/throttled/utils"
5
6
 
6
7
  module Sidekiq
7
8
  module Throttled
@@ -13,6 +14,8 @@ module Sidekiq
13
14
  @aliases = {}
14
15
 
15
16
  class << self
17
+ include Utils
18
+
16
19
  # Adds strategy to the registry.
17
20
  #
18
21
  # @note prints a warning to STDERR upon duplicate strategy name
@@ -49,12 +52,15 @@ module Sidekiq
49
52
  #
50
53
  # @overload get(name, &block)
51
54
  # Yields control to the block if requested strategy was found.
55
+ # @param [#to_s] name
52
56
  # @yieldparam [Strategy] strategy
53
57
  # @yield [strategy] Gives found strategy to the block
54
58
  # @return result of a block
55
59
  def get(name)
56
- strategy = @strategies[name.to_s] || @aliases[name.to_s]
60
+ strategy = find(name.to_s) || find_by_class(name)
61
+
57
62
  return yield strategy if strategy && block_given?
63
+
58
64
  strategy
59
65
  end
60
66
 
@@ -86,6 +92,34 @@ module Sidekiq
86
92
  yield(name, strategy) unless strategy.dynamic?
87
93
  end
88
94
  end
95
+
96
+ private
97
+
98
+ # Find strategy by it's name.
99
+ #
100
+ # @param name [String]
101
+ # @return [Strategy, nil]
102
+ def find(name)
103
+ @strategies[name] || @aliases[name]
104
+ end
105
+
106
+ # Find strategy by class or it's parents.
107
+ #
108
+ # @param name [Class, #to_s]
109
+ # @return [Strategy, nil]
110
+ def find_by_class(name)
111
+ return unless Throttled.configuration.inherit_strategies?
112
+
113
+ const = name.is_a?(Class) ? name : constantize(name)
114
+ return unless const.is_a?(Class)
115
+
116
+ const.ancestors.each do |m|
117
+ strategy = find(m.name)
118
+ return strategy if strategy
119
+ end
120
+
121
+ nil
122
+ end
89
123
  end
90
124
  end
91
125
  end
@@ -42,7 +42,9 @@ module Sidekiq
42
42
 
43
43
  # @return [Boolean] whenever job is throttled or not
44
44
  def throttled?(jid, *job_args)
45
- return false unless (job_limit = limit(job_args))
45
+ job_limit = limit(job_args)
46
+ return false unless job_limit
47
+ return true if job_limit <= 0
46
48
 
47
49
  kwargs = {
48
50
  :keys => [key(job_args)],
@@ -58,7 +58,9 @@ module Sidekiq
58
58
 
59
59
  # @return [Boolean] whenever job is throttled or not
60
60
  def throttled?(*job_args)
61
- return false unless (job_limit = limit(job_args))
61
+ job_limit = limit(job_args)
62
+ return false unless job_limit
63
+ return true if job_limit <= 0
62
64
 
63
65
  kwargs = {
64
66
  :keys => [key(job_args)],
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sidekiq
4
+ module Throttled
5
+ module Utils
6
+ module_function
7
+
8
+ # Resolve constant from it's name
9
+ # @param name [#to_s] Constant name
10
+ # @return [Object, nil] Resolved constant or nil if failed.
11
+ def constantize(name)
12
+ name.to_s.sub(/^::/, "").split("::").inject(Object, &:const_get)
13
+ rescue NameError
14
+ Sidekiq.logger.warn { "Failed to constantize: #{name}" }
15
+ nil
16
+ end
17
+ end
18
+ end
19
+ end
@@ -3,6 +3,6 @@
3
3
  module Sidekiq
4
4
  module Throttled
5
5
  # Gem version
6
- VERSION = "0.10.0.beta"
6
+ VERSION = "0.10.0"
7
7
  end
8
8
  end
@@ -28,5 +28,5 @@ Gem::Specification.new do |spec|
28
28
  spec.add_runtime_dependency "redis-prescription"
29
29
  spec.add_runtime_dependency "sidekiq"
30
30
 
31
- spec.add_development_dependency "bundler", "~> 1.10"
31
+ spec.add_development_dependency "bundler", "~> 2.0"
32
32
  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.10.0.beta
4
+ version: 0.10.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: 2018-09-27 00:00:00.000000000 Z
11
+ date: 2019-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '1.10'
61
+ version: '2.0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '1.10'
68
+ version: '2.0'
69
69
  description: Concurrency and threshold throttling for Sidekiq.
70
70
  email:
71
71
  - ixti@member.fsf.org
@@ -94,6 +94,7 @@ files:
94
94
  - lib/sidekiq/throttled/communicator.rb
95
95
  - lib/sidekiq/throttled/communicator/callbacks.rb
96
96
  - lib/sidekiq/throttled/communicator/listener.rb
97
+ - lib/sidekiq/throttled/configuration.rb
97
98
  - lib/sidekiq/throttled/errors.rb
98
99
  - lib/sidekiq/throttled/expirable_list.rb
99
100
  - lib/sidekiq/throttled/fetch.rb
@@ -110,6 +111,7 @@ files:
110
111
  - lib/sidekiq/throttled/strategy/threshold.lua
111
112
  - lib/sidekiq/throttled/strategy/threshold.rb
112
113
  - lib/sidekiq/throttled/testing.rb
114
+ - lib/sidekiq/throttled/utils.rb
113
115
  - lib/sidekiq/throttled/version.rb
114
116
  - lib/sidekiq/throttled/web.rb
115
117
  - lib/sidekiq/throttled/web/queues.html.erb
@@ -134,12 +136,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
134
136
  version: '0'
135
137
  required_rubygems_version: !ruby/object:Gem::Requirement
136
138
  requirements:
137
- - - ">"
139
+ - - ">="
138
140
  - !ruby/object:Gem::Version
139
- version: 1.3.1
141
+ version: '0'
140
142
  requirements: []
141
- rubyforge_project:
142
- rubygems_version: 2.7.6
143
+ rubygems_version: 3.0.3
143
144
  signing_key:
144
145
  specification_version: 4
145
146
  summary: Concurrency and threshold throttling for Sidekiq.