sidekiq-throttled 1.0.0.alpha → 1.0.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 +4 -4
- data/README.adoc +20 -2
- data/lib/sidekiq/throttled/config.rb +44 -0
- data/lib/sidekiq/throttled/cooldown.rb +55 -0
- data/lib/sidekiq/throttled/expirable_set.rb +70 -0
- data/lib/sidekiq/throttled/job.rb +3 -3
- data/lib/sidekiq/throttled/middleware.rb +8 -3
- data/lib/sidekiq/throttled/patches/basic_fetch.rb +53 -0
- data/lib/sidekiq/throttled/registry.rb +2 -2
- data/lib/sidekiq/throttled/strategy_collection.rb +1 -2
- data/lib/sidekiq/throttled/version.rb +1 -1
- data/lib/sidekiq/throttled.rb +39 -26
- metadata +27 -12
- data/lib/sidekiq/throttled/basic_fetch.rb +0 -55
- data/lib/sidekiq/throttled/configuration.rb +0 -50
- data/lib/sidekiq/throttled/fetch.rb +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c7e45d38e16a4fd149ab2a5df541308d54304ae35bbd337d3701e534bffa025b
|
4
|
+
data.tar.gz: 7aa8a7a9469dbec0d06df4829dee111f015119861ac0caff00ca70148d014602
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 29e1a58bf302daeacb18695a618e55eec6ec177112274ac5dc85f7fbc1b14cb56c1bb8f8e9250dd22683182c8baee0d95c40f3708dba8518a5dde7cfbc71bbb6
|
7
|
+
data.tar.gz: 24ada7f5c9ee65400d1442feb72f95428ef9efdaf7aac2d38b732b2f4d649709712fb25d6b97e2c59627647bdcadf4c5d206fbb46f9b8321a5d293184866f2d2
|
data/README.adoc
CHANGED
@@ -89,6 +89,25 @@ end
|
|
89
89
|
----
|
90
90
|
|
91
91
|
|
92
|
+
=== Configuration
|
93
|
+
|
94
|
+
[source,ruby]
|
95
|
+
----
|
96
|
+
Sidekiq::Throttled.configure do |config|
|
97
|
+
# Period in seconds to exclude queue from polling in case it returned
|
98
|
+
# {config.cooldown_threshold} amount of throttled jobs in a row. Set
|
99
|
+
# this value to `nil` to disable cooldown manager completely.
|
100
|
+
# Default: 2.0
|
101
|
+
config.cooldown_period = 2.0
|
102
|
+
|
103
|
+
# Exclude queue from polling after it returned given amount of throttled
|
104
|
+
# jobs in a row.
|
105
|
+
# Default: 1 (cooldown after first throttled job)
|
106
|
+
config.cooldown_threshold = 1
|
107
|
+
end
|
108
|
+
----
|
109
|
+
|
110
|
+
|
92
111
|
=== Observer
|
93
112
|
|
94
113
|
You can specify an observer that will be called on throttling. To do so pass an
|
@@ -232,7 +251,6 @@ sidekiq_throttle(concurrency: { limit: 20, ttl: 1.hour.to_i })
|
|
232
251
|
|
233
252
|
This library aims to support and is tested against the following Ruby versions:
|
234
253
|
|
235
|
-
* Ruby 2.7.x
|
236
254
|
* Ruby 3.0.x
|
237
255
|
* Ruby 3.1.x
|
238
256
|
* Ruby 3.2.x
|
@@ -255,9 +273,9 @@ dropped.
|
|
255
273
|
|
256
274
|
This library aims to support and work with following Sidekiq versions:
|
257
275
|
|
258
|
-
* Sidekiq 6.5.x
|
259
276
|
* Sidekiq 7.0.x
|
260
277
|
* Sidekiq 7.1.x
|
278
|
+
* Sidekiq 7.2.x
|
261
279
|
|
262
280
|
|
263
281
|
== Development
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sidekiq
|
4
|
+
module Throttled
|
5
|
+
# Configuration object.
|
6
|
+
class Config
|
7
|
+
# Period in seconds to exclude queue from polling in case it returned
|
8
|
+
# {#cooldown_threshold} amount of throttled jobs in a row.
|
9
|
+
#
|
10
|
+
# Set this to `nil` to disable cooldown completely.
|
11
|
+
#
|
12
|
+
# @return [Float, nil]
|
13
|
+
attr_reader :cooldown_period
|
14
|
+
|
15
|
+
# Amount of throttled jobs returned from the queue subsequently after
|
16
|
+
# which queue will be excluded from polling for the durations of
|
17
|
+
# {#cooldown_period}.
|
18
|
+
#
|
19
|
+
# @return [Integer]
|
20
|
+
attr_reader :cooldown_threshold
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
@cooldown_period = 2.0
|
24
|
+
@cooldown_threshold = 1
|
25
|
+
end
|
26
|
+
|
27
|
+
# @!attribute [w] cooldown_period
|
28
|
+
def cooldown_period=(value)
|
29
|
+
raise TypeError, "unexpected type #{value.class}" unless value.nil? || value.is_a?(Float)
|
30
|
+
raise ArgumentError, "period must be positive" unless value.nil? || value.positive?
|
31
|
+
|
32
|
+
@cooldown_period = value
|
33
|
+
end
|
34
|
+
|
35
|
+
# @!attribute [w] cooldown_threshold
|
36
|
+
def cooldown_threshold=(value)
|
37
|
+
raise TypeError, "unexpected type #{value.class}" unless value.is_a?(Integer)
|
38
|
+
raise ArgumentError, "threshold must be positive" unless value.positive?
|
39
|
+
|
40
|
+
@cooldown_threshold = value
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "concurrent"
|
4
|
+
|
5
|
+
require_relative "./expirable_set"
|
6
|
+
|
7
|
+
module Sidekiq
|
8
|
+
module Throttled
|
9
|
+
# @api internal
|
10
|
+
#
|
11
|
+
# Queues cooldown manager. Tracks list of queues that should be temporarily
|
12
|
+
# (for the duration of {Config#cooldown_period}) excluded from polling.
|
13
|
+
class Cooldown
|
14
|
+
class << self
|
15
|
+
# Returns new {Cooldown} instance if {Config#cooldown_period} is not `nil`.
|
16
|
+
#
|
17
|
+
# @param config [Config]
|
18
|
+
# @return [Cooldown, nil]
|
19
|
+
def [](config)
|
20
|
+
new(config) if config.cooldown_period
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# @param config [Config]
|
25
|
+
def initialize(config)
|
26
|
+
@queues = ExpirableSet.new(config.cooldown_period)
|
27
|
+
@threshold = config.cooldown_threshold
|
28
|
+
@tracker = Concurrent::Map.new
|
29
|
+
end
|
30
|
+
|
31
|
+
# Notify that given queue returned job that was throttled.
|
32
|
+
#
|
33
|
+
# @param queue [String]
|
34
|
+
# @return [void]
|
35
|
+
def notify_throttled(queue)
|
36
|
+
@queues.add(queue) if @threshold <= @tracker.merge_pair(queue, 1, &:succ)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Notify that given queue returned job that was not throttled.
|
40
|
+
#
|
41
|
+
# @param queue [String]
|
42
|
+
# @return [void]
|
43
|
+
def notify_admitted(queue)
|
44
|
+
@tracker.delete(queue)
|
45
|
+
end
|
46
|
+
|
47
|
+
# List of queues that should not be polled
|
48
|
+
#
|
49
|
+
# @return [Array<String>]
|
50
|
+
def queues
|
51
|
+
@queues.to_a
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "concurrent"
|
4
|
+
|
5
|
+
module Sidekiq
|
6
|
+
module Throttled
|
7
|
+
# @api internal
|
8
|
+
#
|
9
|
+
# Set of elements with expirations.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# set = ExpirableSet.new(10.0)
|
13
|
+
# set.add("a")
|
14
|
+
# sleep(5)
|
15
|
+
# set.add("b")
|
16
|
+
# set.to_a # => ["a", "b"]
|
17
|
+
# sleep(5)
|
18
|
+
# set.to_a # => ["b"]
|
19
|
+
class ExpirableSet
|
20
|
+
include Enumerable
|
21
|
+
|
22
|
+
# @param ttl [Float] expiration is seconds
|
23
|
+
# @raise [ArgumentError] if `ttl` is not positive Float
|
24
|
+
def initialize(ttl)
|
25
|
+
raise ArgumentError, "ttl must be positive Float" unless ttl.is_a?(Float) && ttl.positive?
|
26
|
+
|
27
|
+
@elements = Concurrent::Map.new
|
28
|
+
@ttl = ttl
|
29
|
+
end
|
30
|
+
|
31
|
+
# @param element [Object]
|
32
|
+
# @return [ExpirableSet] self
|
33
|
+
def add(element)
|
34
|
+
# cleanup expired elements to avoid mem-leak
|
35
|
+
horizon = now
|
36
|
+
expired = @elements.each_pair.select { |(_, sunset)| expired?(sunset, horizon) }
|
37
|
+
expired.each { |pair| @elements.delete_pair(*pair) }
|
38
|
+
|
39
|
+
# add new element
|
40
|
+
@elements[element] = now + @ttl
|
41
|
+
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
# @yield [Object] Gives each live (not expired) element to the block
|
46
|
+
def each
|
47
|
+
return to_enum __method__ unless block_given?
|
48
|
+
|
49
|
+
horizon = now
|
50
|
+
|
51
|
+
@elements.each_pair do |element, sunset|
|
52
|
+
yield element unless expired?(sunset, horizon)
|
53
|
+
end
|
54
|
+
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
# @return [Float]
|
61
|
+
def now
|
62
|
+
::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
63
|
+
end
|
64
|
+
|
65
|
+
def expired?(sunset, horizon)
|
66
|
+
sunset <= horizon
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -13,7 +13,7 @@ module Sidekiq
|
|
13
13
|
# include Sidekiq::Job
|
14
14
|
# include Sidekiq::Throttled::Job
|
15
15
|
#
|
16
|
-
#
|
16
|
+
# sidekiq_options :queue => :my_queue
|
17
17
|
# sidekiq_throttle :threshold => { :limit => 123, :period => 1.hour }
|
18
18
|
#
|
19
19
|
# def perform
|
@@ -29,8 +29,8 @@ module Sidekiq
|
|
29
29
|
# in order to make API inline with `include Sidekiq::Job`.
|
30
30
|
#
|
31
31
|
# @private
|
32
|
-
def self.included(
|
33
|
-
|
32
|
+
def self.included(base)
|
33
|
+
base.extend(ClassMethods)
|
34
34
|
end
|
35
35
|
|
36
36
|
# Helper methods added to the singleton class of destination
|
@@ -9,14 +9,19 @@ module Sidekiq
|
|
9
9
|
#
|
10
10
|
# @private
|
11
11
|
class Middleware
|
12
|
-
include Sidekiq::ServerMiddleware
|
12
|
+
include Sidekiq::ServerMiddleware
|
13
13
|
|
14
14
|
# Called within Sidekiq job processing
|
15
15
|
def call(_worker, msg, _queue)
|
16
16
|
yield
|
17
17
|
ensure
|
18
|
-
|
19
|
-
|
18
|
+
job = msg.fetch("wrapped") { msg["class"] }
|
19
|
+
jid = msg["jid"]
|
20
|
+
|
21
|
+
if job && jid
|
22
|
+
Registry.get job do |strategy|
|
23
|
+
strategy.finalize!(jid, *msg["args"])
|
24
|
+
end
|
20
25
|
end
|
21
26
|
end
|
22
27
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "sidekiq"
|
4
|
+
require "sidekiq/fetch"
|
5
|
+
|
6
|
+
module Sidekiq
|
7
|
+
module Throttled
|
8
|
+
module Patches
|
9
|
+
module BasicFetch
|
10
|
+
# Retrieves job from redis.
|
11
|
+
#
|
12
|
+
# @return [Sidekiq::Throttled::UnitOfWork, nil]
|
13
|
+
def retrieve_work
|
14
|
+
work = super
|
15
|
+
|
16
|
+
if work && Throttled.throttled?(work.job)
|
17
|
+
Throttled.cooldown&.notify_throttled(work.queue)
|
18
|
+
requeue_throttled(work)
|
19
|
+
return nil
|
20
|
+
end
|
21
|
+
|
22
|
+
Throttled.cooldown&.notify_admitted(work.queue) if work
|
23
|
+
|
24
|
+
work
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# Pushes job back to the head of the queue, so that job won't be tried
|
30
|
+
# immediately after it was requeued (in most cases).
|
31
|
+
#
|
32
|
+
# @note This is triggered when job is throttled. So it is same operation
|
33
|
+
# Sidekiq performs upon `Sidekiq::Worker.perform_async` call.
|
34
|
+
#
|
35
|
+
# @return [void]
|
36
|
+
def requeue_throttled(work)
|
37
|
+
redis { |conn| conn.lpush(work.queue, work.job) }
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns list of queues to try to fetch jobs from.
|
41
|
+
#
|
42
|
+
# @note It may return an empty array.
|
43
|
+
# @param [Array<String>] queues
|
44
|
+
# @return [Array<String>]
|
45
|
+
def queues_cmd
|
46
|
+
super - (Throttled.cooldown&.queues || [])
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
Sidekiq::BasicFetch.prepend(Sidekiq::Throttled::Patches::BasicFetch)
|
@@ -102,8 +102,6 @@ module Sidekiq
|
|
102
102
|
# @param name [Class, #to_s]
|
103
103
|
# @return [Strategy, nil]
|
104
104
|
def find_by_class(name)
|
105
|
-
return unless Throttled.configuration.inherit_strategies?
|
106
|
-
|
107
105
|
const = name.is_a?(Class) ? name : Object.const_get(name)
|
108
106
|
return unless const.is_a?(Class)
|
109
107
|
|
@@ -112,6 +110,8 @@ module Sidekiq
|
|
112
110
|
return strategy if strategy
|
113
111
|
end
|
114
112
|
|
113
|
+
nil
|
114
|
+
rescue NameError
|
115
115
|
nil
|
116
116
|
end
|
117
117
|
end
|
@@ -19,8 +19,7 @@ module Sidekiq
|
|
19
19
|
# @param [#to_s] name
|
20
20
|
# @param [#call] key_suffix Dynamic key suffix generator.
|
21
21
|
def initialize(strategies, strategy:, name:, key_suffix:)
|
22
|
-
strategies = (strategies.is_a?(Hash) ? [strategies] : Array(strategies))
|
23
|
-
@strategies = strategies.map do |options|
|
22
|
+
@strategies = (strategies.is_a?(Hash) ? [strategies] : Array(strategies)).map do |options|
|
24
23
|
make_strategy(strategy, name, key_suffix, options)
|
25
24
|
end
|
26
25
|
end
|
data/lib/sidekiq/throttled.rb
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# 3rd party
|
4
3
|
require "sidekiq"
|
5
4
|
|
6
|
-
|
7
|
-
require_relative "./throttled/
|
8
|
-
require_relative "./throttled/configuration"
|
9
|
-
require_relative "./throttled/fetch"
|
10
|
-
require_relative "./throttled/registry"
|
5
|
+
require_relative "./throttled/config"
|
6
|
+
require_relative "./throttled/cooldown"
|
11
7
|
require_relative "./throttled/job"
|
12
8
|
require_relative "./throttled/middleware"
|
9
|
+
require_relative "./throttled/patches/basic_fetch"
|
10
|
+
require_relative "./throttled/registry"
|
11
|
+
require_relative "./throttled/version"
|
13
12
|
require_relative "./throttled/worker"
|
14
13
|
|
15
14
|
# @see https://github.com/mperham/sidekiq/
|
@@ -42,21 +41,39 @@ module Sidekiq
|
|
42
41
|
# end
|
43
42
|
# end
|
44
43
|
module Throttled
|
44
|
+
MUTEX = Mutex.new
|
45
|
+
private_constant :MUTEX
|
46
|
+
|
47
|
+
@config = Config.new.freeze
|
48
|
+
@cooldown = Cooldown[@config]
|
49
|
+
|
45
50
|
class << self
|
46
|
-
# @
|
47
|
-
|
48
|
-
|
49
|
-
|
51
|
+
# @api internal
|
52
|
+
#
|
53
|
+
# @return [Cooldown, nil]
|
54
|
+
attr_reader :cooldown
|
50
55
|
|
51
|
-
#
|
56
|
+
# @example
|
57
|
+
# Sidekiq::Throttled.configure do |config|
|
58
|
+
# config.cooldown_period = nil # Disable queues cooldown manager
|
59
|
+
# end
|
52
60
|
#
|
53
|
-
# @
|
61
|
+
# @yieldparam config [Config]
|
62
|
+
def configure
|
63
|
+
MUTEX.synchronize do
|
64
|
+
config = @config.dup
|
65
|
+
|
66
|
+
yield config
|
67
|
+
|
68
|
+
@config = config.freeze
|
69
|
+
@cooldown = Cooldown[@config]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
54
73
|
def setup!
|
55
74
|
Sidekiq.configure_server do |config|
|
56
|
-
|
57
|
-
|
58
|
-
else
|
59
|
-
config[:fetch] = Sidekiq::Throttled::Fetch.new(config)
|
75
|
+
config.server_middleware do |chain|
|
76
|
+
chain.add Sidekiq::Throttled::Middleware
|
60
77
|
end
|
61
78
|
end
|
62
79
|
end
|
@@ -66,11 +83,13 @@ module Sidekiq
|
|
66
83
|
# @param [String] message Job's JSON payload
|
67
84
|
# @return [Boolean]
|
68
85
|
def throttled?(message)
|
69
|
-
message =
|
70
|
-
job
|
71
|
-
jid
|
86
|
+
message = Sidekiq.load_json(message)
|
87
|
+
job = message.fetch("wrapped") { message["class"] }
|
88
|
+
jid = message["jid"]
|
72
89
|
|
73
|
-
|
90
|
+
return false unless job && jid
|
91
|
+
|
92
|
+
Registry.get(job) do |strategy|
|
74
93
|
return strategy.throttled?(jid, *message["args"])
|
75
94
|
end
|
76
95
|
|
@@ -80,10 +99,4 @@ module Sidekiq
|
|
80
99
|
end
|
81
100
|
end
|
82
101
|
end
|
83
|
-
|
84
|
-
configure_server do |config|
|
85
|
-
config.server_middleware do |chain|
|
86
|
-
chain.add Sidekiq::Throttled::Middleware
|
87
|
-
end
|
88
|
-
end
|
89
102
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidekiq-throttled
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexey Zapparov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-11-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: concurrent-ruby
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.2.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.2.0
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: redis-prescription
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -30,14 +44,14 @@ dependencies:
|
|
30
44
|
requirements:
|
31
45
|
- - ">="
|
32
46
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
47
|
+
version: '7.0'
|
34
48
|
type: :runtime
|
35
49
|
prerelease: false
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
52
|
- - ">="
|
39
53
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
54
|
+
version: '7.0'
|
41
55
|
description:
|
42
56
|
email:
|
43
57
|
- alexey@zapparov.com
|
@@ -48,12 +62,13 @@ files:
|
|
48
62
|
- LICENSE
|
49
63
|
- README.adoc
|
50
64
|
- lib/sidekiq/throttled.rb
|
51
|
-
- lib/sidekiq/throttled/
|
52
|
-
- lib/sidekiq/throttled/
|
65
|
+
- lib/sidekiq/throttled/config.rb
|
66
|
+
- lib/sidekiq/throttled/cooldown.rb
|
53
67
|
- lib/sidekiq/throttled/errors.rb
|
54
|
-
- lib/sidekiq/throttled/
|
68
|
+
- lib/sidekiq/throttled/expirable_set.rb
|
55
69
|
- lib/sidekiq/throttled/job.rb
|
56
70
|
- lib/sidekiq/throttled/middleware.rb
|
71
|
+
- lib/sidekiq/throttled/patches/basic_fetch.rb
|
57
72
|
- lib/sidekiq/throttled/registry.rb
|
58
73
|
- lib/sidekiq/throttled/strategy.rb
|
59
74
|
- lib/sidekiq/throttled/strategy/base.rb
|
@@ -72,9 +87,9 @@ licenses:
|
|
72
87
|
- MIT
|
73
88
|
metadata:
|
74
89
|
homepage_uri: https://github.com/ixti/sidekiq-throttled
|
75
|
-
source_code_uri: https://github.com/ixti/sidekiq-throttled/tree/v1.0.0
|
90
|
+
source_code_uri: https://github.com/ixti/sidekiq-throttled/tree/v1.0.0
|
76
91
|
bug_tracker_uri: https://github.com/ixti/sidekiq-throttled/issues
|
77
|
-
changelog_uri: https://github.com/ixti/sidekiq-throttled/blob/v1.0.0
|
92
|
+
changelog_uri: https://github.com/ixti/sidekiq-throttled/blob/v1.0.0/CHANGES.md
|
78
93
|
rubygems_mfa_required: 'true'
|
79
94
|
post_install_message:
|
80
95
|
rdoc_options: []
|
@@ -84,12 +99,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
84
99
|
requirements:
|
85
100
|
- - ">="
|
86
101
|
- !ruby/object:Gem::Version
|
87
|
-
version: '
|
102
|
+
version: '3.0'
|
88
103
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
104
|
requirements:
|
90
|
-
- - "
|
105
|
+
- - ">="
|
91
106
|
- !ruby/object:Gem::Version
|
92
|
-
version:
|
107
|
+
version: '0'
|
93
108
|
requirements: []
|
94
109
|
rubygems_version: 3.4.10
|
95
110
|
signing_key:
|
@@ -1,55 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "sidekiq"
|
4
|
-
require "sidekiq/fetch"
|
5
|
-
|
6
|
-
module Sidekiq
|
7
|
-
module Throttled
|
8
|
-
# Default Sidekiq's BasicFetch infused with Throttler.
|
9
|
-
#
|
10
|
-
# @private
|
11
|
-
class BasicFetch < Sidekiq::BasicFetch
|
12
|
-
# Retrieves job from redis.
|
13
|
-
#
|
14
|
-
# @return [Sidekiq::Throttled::UnitOfWork, nil]
|
15
|
-
def retrieve_work
|
16
|
-
work = super
|
17
|
-
|
18
|
-
if work && Throttled.throttled?(work.job)
|
19
|
-
requeue_throttled(work)
|
20
|
-
return nil
|
21
|
-
end
|
22
|
-
|
23
|
-
work
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
# Pushes job back to the head of the queue, so that job won't be tried
|
29
|
-
# immediately after it was requeued (in most cases).
|
30
|
-
#
|
31
|
-
# @note This is triggered when job is throttled. So it is same operation
|
32
|
-
# Sidekiq performs upon `Sidekiq::Worker.perform_async` call.
|
33
|
-
#
|
34
|
-
# @return [void]
|
35
|
-
def requeue_throttled(work)
|
36
|
-
redis { |conn| conn.lpush(work.queue, work.job) }
|
37
|
-
end
|
38
|
-
|
39
|
-
# Returns list of queues to try to fetch jobs from.
|
40
|
-
#
|
41
|
-
# @note It may return an empty array.
|
42
|
-
# @param [Array<String>] queues
|
43
|
-
# @return [Array<String>]
|
44
|
-
def queues_cmd
|
45
|
-
queues = super
|
46
|
-
|
47
|
-
# TODO: Refactor to be prepended as an integration mixin during configuration stage
|
48
|
-
# Or via configurable queues reducer
|
49
|
-
queues -= Sidekiq::Pauzer.paused_queues.map { |name| "queue:#{name}" } if defined?(Sidekiq::Pauzer)
|
50
|
-
|
51
|
-
queues
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
@@ -1,50 +0,0 @@
|
|
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 FooJob
|
25
|
-
# include Sidekiq::Job
|
26
|
-
# include Sidekiq::Throttled::Job
|
27
|
-
#
|
28
|
-
# sidekiq_throttle :concurrency => { :limit => 42 }
|
29
|
-
# end
|
30
|
-
#
|
31
|
-
# class BarJob < FooJob
|
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
|