sidekiq-throttled 0.18.0 → 1.1.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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +314 -0
  3. data/lib/sidekiq/throttled/config.rb +44 -0
  4. data/lib/sidekiq/throttled/cooldown.rb +55 -0
  5. data/lib/sidekiq/throttled/expirable_set.rb +70 -0
  6. data/lib/sidekiq/throttled/job.rb +4 -4
  7. data/lib/sidekiq/throttled/middlewares/server.rb +28 -0
  8. data/lib/sidekiq/throttled/patches/basic_fetch.rb +53 -0
  9. data/lib/sidekiq/throttled/registry.rb +4 -7
  10. data/lib/sidekiq/throttled/strategy/concurrency.rb +2 -4
  11. data/lib/sidekiq/throttled/strategy/threshold.rb +2 -4
  12. data/lib/sidekiq/throttled/strategy.rb +10 -10
  13. data/lib/sidekiq/throttled/strategy_collection.rb +2 -3
  14. data/lib/sidekiq/throttled/version.rb +1 -1
  15. data/lib/sidekiq/throttled/web.rb +2 -45
  16. data/lib/sidekiq/throttled/worker.rb +1 -1
  17. data/lib/sidekiq/throttled.rb +45 -57
  18. metadata +22 -67
  19. data/.coveralls.yml +0 -1
  20. data/.github/dependabot.yml +0 -12
  21. data/.github/workflows/ci.yml +0 -52
  22. data/.gitignore +0 -12
  23. data/.rspec +0 -5
  24. data/.rubocop.yml +0 -20
  25. data/.rubocop_todo.yml +0 -68
  26. data/.travis.yml +0 -37
  27. data/.yardopts +0 -1
  28. data/Appraisals +0 -9
  29. data/CHANGES.md +0 -318
  30. data/Gemfile +0 -34
  31. data/Guardfile +0 -25
  32. data/README.md +0 -297
  33. data/Rakefile +0 -27
  34. data/gemfiles/sidekiq_6.4.gemfile +0 -33
  35. data/gemfiles/sidekiq_6.5.gemfile +0 -33
  36. data/lib/sidekiq/throttled/communicator/callbacks.rb +0 -72
  37. data/lib/sidekiq/throttled/communicator/exception_handler.rb +0 -25
  38. data/lib/sidekiq/throttled/communicator/listener.rb +0 -109
  39. data/lib/sidekiq/throttled/communicator.rb +0 -116
  40. data/lib/sidekiq/throttled/configuration.rb +0 -50
  41. data/lib/sidekiq/throttled/expirable_list.rb +0 -70
  42. data/lib/sidekiq/throttled/fetch/unit_of_work.rb +0 -83
  43. data/lib/sidekiq/throttled/fetch.rb +0 -94
  44. data/lib/sidekiq/throttled/middleware.rb +0 -22
  45. data/lib/sidekiq/throttled/patches/queue.rb +0 -18
  46. data/lib/sidekiq/throttled/queue_name.rb +0 -46
  47. data/lib/sidekiq/throttled/queues_pauser.rb +0 -152
  48. data/lib/sidekiq/throttled/testing.rb +0 -12
  49. data/lib/sidekiq/throttled/utils.rb +0 -19
  50. data/lib/sidekiq/throttled/web/queues.html.erb +0 -49
  51. data/lib/sidekiq/throttled/web/summary_fix.js +0 -10
  52. data/lib/sidekiq/throttled/web/summary_fix.rb +0 -35
  53. data/rubocop/layout.yml +0 -24
  54. data/rubocop/lint.yml +0 -41
  55. data/rubocop/metrics.yml +0 -4
  56. data/rubocop/performance.yml +0 -25
  57. data/rubocop/rspec.yml +0 -3
  58. data/rubocop/style.yml +0 -84
  59. data/sidekiq-throttled.gemspec +0 -36
  60. /data/{LICENSE.md → LICENSE.txt} +0 -0
@@ -1,33 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "appraisal"
6
- gem "rake"
7
- gem "rspec"
8
- gem "sidekiq", "~> 6.4.0"
9
-
10
- group :development do
11
- gem "byebug"
12
- gem "guard", require: false
13
- gem "guard-rspec", require: false
14
- gem "guard-rubocop", require: false
15
- end
16
-
17
- group :test do
18
- gem "apparition"
19
- gem "capybara"
20
- gem "puma"
21
- gem "rack-test"
22
- gem "sinatra"
23
- gem "timecop"
24
- end
25
-
26
- group :lint do
27
- gem "rubocop", require: false
28
- gem "rubocop-performance", require: false
29
- gem "rubocop-rake", require: false
30
- gem "rubocop-rspec", require: false
31
- end
32
-
33
- gemspec path: "../"
@@ -1,33 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "appraisal"
6
- gem "rake"
7
- gem "rspec"
8
- gem "sidekiq", "~> 6.5.0"
9
-
10
- group :development do
11
- gem "byebug"
12
- gem "guard", require: false
13
- gem "guard-rspec", require: false
14
- gem "guard-rubocop", require: false
15
- end
16
-
17
- group :test do
18
- gem "apparition"
19
- gem "capybara"
20
- gem "puma"
21
- gem "rack-test"
22
- gem "sinatra"
23
- gem "timecop"
24
- end
25
-
26
- group :lint do
27
- gem "rubocop", require: false
28
- gem "rubocop-performance", require: false
29
- gem "rubocop-rake", require: false
30
- gem "rubocop-rspec", require: false
31
- end
32
-
33
- gemspec path: "../"
@@ -1,72 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "fiber"
4
-
5
- require "sidekiq/throttled/communicator/exception_handler"
6
-
7
- module Sidekiq
8
- module Throttled
9
- class Communicator
10
- # Callbacks registry and runner. Runs registered callbacks in dedicated
11
- # Fiber solving issue with ConnectionPool and Redis client in subscriber
12
- # mode.
13
- #
14
- # Once Redis entered subscriber mode `#subscribe` method, it can't be used
15
- # for any command but pub/sub or quit, making it impossible to use for
16
- # anything else. ConnectionPool binds reserved client to Thread, thus
17
- # nested `#with` calls inside same thread result into a same connection.
18
- # That makes it impossible to issue any normal Redis commands from
19
- # within listener Thread.
20
- #
21
- # @private
22
- class Callbacks
23
- include ExceptionHandler
24
-
25
- # Initializes callbacks registry.
26
- def initialize
27
- @mutex = Mutex.new
28
- @handlers = Hash.new { |h, k| h[k] = [] }
29
- end
30
-
31
- # Registers handler of given event.
32
- #
33
- # @example
34
- #
35
- # callbacks.on "and out comes wolves" do |who|
36
- # puts "#{who} let the dogs out?!"
37
- # end
38
- #
39
- # @param [#to_s] event
40
- # @raise [ArgumentError] if no handler block given
41
- # @yield [*args] Runs given block upon `event`
42
- # @yieldreturn [void]
43
- # @return [self]
44
- def on(event, &handler)
45
- raise ArgumentError, "No block given" unless handler
46
-
47
- @mutex.synchronize { @handlers[event.to_s] << handler }
48
- self
49
- end
50
-
51
- # Runs event handlers with given args.
52
- #
53
- # @param [#to_s] event
54
- # @param [Object] payload
55
- # @return [void]
56
- def run(event, payload = nil)
57
- @mutex.synchronize do
58
- fiber = Fiber.new do
59
- @handlers[event.to_s].each do |callback|
60
- callback.call(payload)
61
- rescue => e
62
- handle_exception(e, :context => "sidekiq:throttled")
63
- end
64
- end
65
-
66
- fiber.resume
67
- end
68
- end
69
- end
70
- end
71
- end
72
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "sidekiq"
4
- require "sidekiq/version"
5
-
6
- module Sidekiq
7
- module Throttled
8
- class Communicator
9
- if Sidekiq::VERSION >= "6.5.0"
10
- module ExceptionHandler
11
- def handle_exception(*args)
12
- Sidekiq.handle_exception(*args)
13
- end
14
- end
15
-
16
- # NOTE: `Sidekiq.default_error_handler` is private API
17
- Sidekiq.error_handlers << Sidekiq.method(:default_error_handler)
18
- else
19
- require "sidekiq/exception_handler"
20
-
21
- ExceptionHandler = ::Sidekiq::ExceptionHandler
22
- end
23
- end
24
- end
25
- end
@@ -1,109 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "sidekiq/throttled/communicator/exception_handler"
4
-
5
- module Sidekiq
6
- module Throttled
7
- class Communicator
8
- # Redis subscription listener thread.
9
- #
10
- # @private
11
- class Listener < Thread
12
- include ExceptionHandler
13
-
14
- # Starts listener thread.
15
- #
16
- # @param [String] channel Redis pub/sub channel to listen
17
- # @param [Callbacks] callbacks Message callbacks registry
18
- def initialize(channel, callbacks)
19
- @channel = channel
20
- @callbacks = callbacks
21
- @terminated = false
22
- @subscribed = false
23
-
24
- super { listen until @terminated }
25
- end
26
-
27
- # Whenever underlying redis client subscribed to pub/sup channel.
28
- #
29
- # @return [Boolean]
30
- def ready?
31
- @subscribed
32
- end
33
-
34
- # Whenever main loop is still running.
35
- #
36
- # @return [Boolean]
37
- def listening?
38
- !@terminated
39
- end
40
-
41
- # Stops listener.
42
- #
43
- # @return [void]
44
- def stop
45
- # Raising exception while client is in subscription mode makes
46
- # redis close connection and thus causing ConnectionPool reopen
47
- # it (normal mode). Otherwise subscription mode client will be
48
- # pushed back to ConnectionPool causing problems.
49
- raise Sidekiq::Shutdown
50
- end
51
-
52
- private
53
-
54
- # Wraps {#subscribe} with exception handlers:
55
- #
56
- # - `Sidekiq::Shutdown` exception marks listener as stopped and returns
57
- # making `while` loop of listener thread terminate.
58
- #
59
- # - `StandardError` got recorded to the log and swallowed,
60
- # making `while` loop of the listener thread restart.
61
- #
62
- # - `Exception` is recorded to the log and re-raised.
63
- #
64
- # @return [void]
65
- def listen # rubocop:disable Metrics/MethodLength
66
- subscribe
67
- rescue Sidekiq::Shutdown
68
- @terminated = true
69
- @subscribed = false
70
- rescue StandardError => e # rubocop:disable Style/RescueStandardError
71
- @subscribed = false
72
- handle_exception(e, { :context => "sidekiq:throttled" })
73
- sleep 1
74
- rescue Exception => e # rubocop:disable Lint/RescueException
75
- @terminated = true
76
- @subscribed = false
77
- handle_exception(e, { :context => "sidekiq:throttled" })
78
- raise
79
- end
80
-
81
- # Subscribes to channel and triggers all registerd handlers for
82
- # received messages.
83
- #
84
- # @note Puts thread's Redis connection to subscription mode and
85
- # locks thread.
86
- #
87
- # @see http://redis.io/topics/pubsub
88
- # @see http://redis.io/commands/subscribe
89
- # @see Callbacks#run
90
- # @return [void]
91
- def subscribe # rubocop:disable Metrics/MethodLength
92
- Sidekiq.redis do |conn|
93
- conn.subscribe @channel do |on|
94
- on.subscribe do
95
- @subscribed = true
96
- @callbacks.run("ready")
97
- end
98
-
99
- on.message do |_channel, data|
100
- message, payload = Marshal.load(data) # rubocop:disable Security/MarshalLoad:
101
- @callbacks.run("message:#{message}", payload)
102
- end
103
- end
104
- end
105
- end
106
- end
107
- end
108
- end
109
- end
@@ -1,116 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "singleton"
4
-
5
- require "sidekiq/throttled/communicator/exception_handler"
6
- require "sidekiq/throttled/communicator/listener"
7
- require "sidekiq/throttled/communicator/callbacks"
8
-
9
- module Sidekiq
10
- module Throttled
11
- # Inter-process communication for sidekiq. It starts listener thread on
12
- # sidekiq server and listens for incoming messages.
13
- #
14
- # @example
15
- #
16
- # # Add incoming message handler for server
17
- # Communicator.instance.receive "knock" do |who|
18
- # puts "#{who}'s knocking on the door"
19
- # end
20
- #
21
- # # Emit message from console
22
- # Sidekiq.redis do |conn|
23
- # Communicator.instance.transmit(conn, "knock", "ixti")
24
- # end
25
- class Communicator
26
- include Singleton
27
- include ExceptionHandler
28
-
29
- # Redis PUB/SUB channel name
30
- #
31
- # @see http://redis.io/topics/pubsub
32
- CHANNEL_NAME = "sidekiq:throttled"
33
- private_constant :CHANNEL_NAME
34
-
35
- # Initializes singleton instance.
36
- def initialize
37
- @callbacks = Callbacks.new
38
- @listener = nil
39
- @mutex = Mutex.new
40
- end
41
-
42
- # Starts listener thread.
43
- #
44
- # @return [void]
45
- def start_listener
46
- @mutex.synchronize do
47
- @listener ||= Listener.new(CHANNEL_NAME, @callbacks)
48
- end
49
- end
50
-
51
- # Stops listener thread.
52
- #
53
- # @return [void]
54
- def stop_listener
55
- @mutex.synchronize do
56
- @listener&.stop
57
- @listener = nil
58
- end
59
- end
60
-
61
- # Configures Sidekiq server to start/stop listener thread.
62
- #
63
- # @private
64
- # @return [void]
65
- def setup!
66
- Sidekiq.configure_server do |config|
67
- config.on(:startup) { start_listener }
68
- config.on(:quiet) { stop_listener }
69
- end
70
- end
71
-
72
- # Transmit message to listeners.
73
- #
74
- # @example
75
- #
76
- # Sidekiq.redis do |conn|
77
- # Communicator.instance.transmit(conn, "knock")
78
- # end
79
- #
80
- # @param [Redis] redis Redis client
81
- # @param [#to_s] message
82
- # @param [Object] payload
83
- # @return [void]
84
- def transmit(redis, message, payload = nil)
85
- redis.publish(CHANNEL_NAME, Marshal.dump([message.to_s, payload]))
86
- end
87
-
88
- # Add incoming message handler.
89
- #
90
- # @example
91
- #
92
- # Communicator.instance.receive "knock" do |payload|
93
- # # do something upon `knock` message
94
- # end
95
- #
96
- # @param [#to_s] message
97
- # @yield [payload] Runs given block everytime `message` being received.
98
- # @yieldparam [Object, nil] payload Payload that was transmitted
99
- # @yieldreturn [void]
100
- # @return [void]
101
- def receive(message, &handler)
102
- @callbacks.on("message:#{message}", &handler)
103
- end
104
-
105
- # Communicator readiness hook.
106
- #
107
- # @yield Runs given block every time listener thread subscribes
108
- # to Redis pub/sub channel.
109
- # @return [void]
110
- def ready(&handler)
111
- @callbacks.on("ready", &handler)
112
- yield if @listener&.ready?
113
- end
114
- end
115
- end
116
- 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
@@ -1,70 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "monitor"
4
-
5
- module Sidekiq
6
- module Throttled
7
- # List that tracks when elements were added and enumerates over those not
8
- # older than `ttl` seconds ago.
9
- #
10
- # ## Implementation
11
- #
12
- # Internally list holds an array of arrays. Thus each element is a tuple of
13
- # monotonic timestamp (when element was added) and element itself:
14
- #
15
- # [
16
- # [ 123456.7890, "default" ],
17
- # [ 123456.7891, "urgent" ],
18
- # [ 123457.9621, "urgent" ],
19
- # ...
20
- # ]
21
- #
22
- # It does not deduplicates elements. Eviction happens only upon elements
23
- # retrieval (see {#each}).
24
- #
25
- # @see https://ruby-doc.org/core/Process.html#method-c-clock_gettime
26
- # @see https://linux.die.net/man/3/clock_gettime
27
- #
28
- # @private
29
- class ExpirableList
30
- include Enumerable
31
-
32
- # @param ttl [Float] elements time-to-live in seconds
33
- def initialize(ttl)
34
- @ttl = ttl.to_f
35
- @arr = []
36
- @mon = Monitor.new
37
- end
38
-
39
- # Pushes given element into the list.
40
- #
41
- # @params element [Object]
42
- # @return [ExpirableList] self
43
- def <<(element)
44
- @mon.synchronize { @arr << [::Process.clock_gettime(::Process::CLOCK_MONOTONIC), element] }
45
- self
46
- end
47
-
48
- # Evicts expired elements and calls the given block once for each element
49
- # left, passing that element as a parameter.
50
- #
51
- # @yield [element]
52
- # @return [Enumerator] if no block given
53
- # @return [ExpirableList] self if block given
54
- def each
55
- return to_enum __method__ unless block_given?
56
-
57
- @mon.synchronize do
58
- horizon = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - @ttl
59
-
60
- # drop all elements older than horizon
61
- @arr.shift while @arr[0] && @arr[0][0] < horizon
62
-
63
- @arr.each { |x| yield x[1] }
64
- end
65
-
66
- self
67
- end
68
- end
69
- end
70
- end
@@ -1,83 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "sidekiq"
4
-
5
- require "sidekiq/throttled/queue_name"
6
-
7
- module Sidekiq
8
- module Throttled
9
- class Fetch
10
- # BRPOP response envelope.
11
- #
12
- # @see Throttled::Fetch
13
- # @private
14
- class UnitOfWork
15
- # @return [String] Redis key where job was pulled from
16
- attr_reader :queue
17
-
18
- # @return [String] Job's JSON payload
19
- attr_reader :job
20
-
21
- # @param [String] queue Redis key where job was pulled from
22
- # @param [String] job Job's JSON payload
23
- def initialize(queue, job)
24
- @queue = queue
25
- @job = job
26
- end
27
-
28
- # Callback that is called by `Sidekiq::Processor` when job was
29
- # succeccfully processed. Most likely this is used by `ReliableFetch`
30
- # of Sidekiq Pro/Enterprise to remove job from running queue.
31
- #
32
- # @return [void]
33
- def acknowledge
34
- # do nothing
35
- end
36
-
37
- # Normalized `queue` name.
38
- #
39
- # @see QueueName.normalize
40
- # @return [String]
41
- def queue_name
42
- @queue_name ||= QueueName.normalize queue
43
- end
44
-
45
- # Pushes job back to the tail of the queue, so that it will be popped
46
- # first next time fetcher will pull job.
47
- #
48
- # @note This is triggered when job was not finished and Sidekiq server
49
- # process was terminated. It is a reverse of whatever fetcher was
50
- # doing to pull the job out of queue.
51
- #
52
- # @param [Redis] pipelined connection for requeing via Redis#pipelined
53
- # @return [void]
54
- def requeue(pipeline = nil)
55
- if pipeline
56
- pipeline.rpush(QueueName.expand(queue_name), job)
57
- else
58
- Sidekiq.redis { |conn| conn.rpush(QueueName.expand(queue_name), job) }
59
- end
60
- end
61
-
62
- # Pushes job back to the head of the queue, so that job won't be tried
63
- # immediately after it was requeued (in most cases).
64
- #
65
- # @note This is triggered when job is throttled. So it is same operation
66
- # Sidekiq performs upon `Sidekiq::Worker.perform_async` call.
67
- #
68
- # @return [void]
69
- def requeue_throttled
70
- Sidekiq.redis { |conn| conn.lpush(QueueName.expand(queue_name), job) }
71
- end
72
-
73
- # Tells whenever job should be pushed back to queue (throttled) or not.
74
- #
75
- # @see Sidekiq::Throttled.throttled?
76
- # @return [Boolean]
77
- def throttled?
78
- Throttled.throttled? job
79
- end
80
- end
81
- end
82
- end
83
- end
@@ -1,94 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "sidekiq"
4
- require "sidekiq/throttled/expirable_list"
5
- require "sidekiq/throttled/fetch/unit_of_work"
6
- require "sidekiq/throttled/queues_pauser"
7
- require "sidekiq/throttled/queue_name"
8
-
9
- module Sidekiq
10
- module Throttled
11
- # Throttled fetch strategy.
12
- #
13
- # @private
14
- class Fetch
15
- # Timeout to sleep between fetch retries in case of no job received,
16
- # as well as timeout to wait for redis to give us something to work.
17
- TIMEOUT = 2
18
-
19
- # Initializes fetcher instance.
20
- # @param options [Hash]
21
- # @option options [Integer] :throttled_queue_cooldown (TIMEOUT)
22
- # Min delay in seconds before queue will be polled again after
23
- # throttled job.
24
- # @option options [Boolean] :strict (false)
25
- # @option options [Array<#to_s>] :queue
26
- def initialize(options)
27
- @paused = ExpirableList.new(options.fetch(:throttled_queue_cooldown, TIMEOUT))
28
-
29
- @strict = options.fetch(:strict, false)
30
- @queues = options.fetch(:queues).map { |q| QueueName.expand q }
31
-
32
- raise ArgumentError, "empty :queues" if @queues.empty?
33
-
34
- @queues.uniq! if @strict
35
- end
36
-
37
- # Retrieves job from redis.
38
- #
39
- # @return [Sidekiq::Throttled::UnitOfWork, nil]
40
- def retrieve_work
41
- work = brpop
42
- return unless work
43
-
44
- work = UnitOfWork.new(*work)
45
- return work unless work.throttled?
46
-
47
- work.requeue_throttled
48
- @paused << QueueName.expand(work.queue_name)
49
-
50
- nil
51
- end
52
-
53
- def bulk_requeue(units, _options)
54
- return if units.empty?
55
-
56
- Sidekiq.logger.debug { "Re-queueing terminated jobs" }
57
- Sidekiq.redis do |conn|
58
- conn.pipelined do |pipeline|
59
- units.each { |unit| unit.requeue(pipeline) }
60
- end
61
- end
62
- Sidekiq.logger.info("Pushed #{units.size} jobs back to Redis")
63
- rescue => e
64
- Sidekiq.logger.warn("Failed to requeue #{units.size} jobs: #{e}")
65
- end
66
-
67
- private
68
-
69
- # Tries to pop pair of `queue` and job `message` out of sidekiq queues.
70
- #
71
- # @see http://redis.io/commands/brpop
72
- # @return [Array(String, String), nil]
73
- def brpop
74
- queues = filter_queues(@strict ? @queues : @queues.shuffle.uniq)
75
-
76
- if queues.empty?
77
- sleep TIMEOUT
78
- return
79
- end
80
-
81
- Sidekiq.redis { |conn| conn.brpop(*queues, :timeout => TIMEOUT) }
82
- end
83
-
84
- # Returns list of queues to try to fetch jobs from.
85
- #
86
- # @note It may return an empty array.
87
- # @param [Array<String>] queues
88
- # @return [Array<String>]
89
- def filter_queues(queues)
90
- QueuesPauser.instance.filter(queues) - @paused.to_a
91
- end
92
- end
93
- end
94
- end