sidekiq-throttled 0.18.0 → 1.0.0.alpha
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.md → README.adoc} +95 -114
- data/lib/sidekiq/throttled/basic_fetch.rb +55 -0
- data/lib/sidekiq/throttled/fetch.rb +3 -87
- data/lib/sidekiq/throttled/job.rb +1 -1
- data/lib/sidekiq/throttled/middleware.rb +3 -1
- data/lib/sidekiq/throttled/registry.rb +2 -5
- data/lib/sidekiq/throttled/strategy/concurrency.rb +2 -4
- data/lib/sidekiq/throttled/strategy/threshold.rb +2 -4
- data/lib/sidekiq/throttled/strategy.rb +10 -10
- data/lib/sidekiq/throttled/strategy_collection.rb +1 -1
- data/lib/sidekiq/throttled/version.rb +1 -1
- data/lib/sidekiq/throttled/web.rb +2 -45
- data/lib/sidekiq/throttled/worker.rb +1 -1
- data/lib/sidekiq/throttled.rb +16 -50
- metadata +17 -77
- data/.coveralls.yml +0 -1
- data/.github/dependabot.yml +0 -12
- data/.github/workflows/ci.yml +0 -52
- data/.gitignore +0 -12
- data/.rspec +0 -5
- data/.rubocop.yml +0 -20
- data/.rubocop_todo.yml +0 -68
- data/.travis.yml +0 -37
- data/.yardopts +0 -1
- data/Appraisals +0 -9
- data/CHANGES.md +0 -318
- data/Gemfile +0 -34
- data/Guardfile +0 -25
- data/Rakefile +0 -27
- data/gemfiles/sidekiq_6.4.gemfile +0 -33
- data/gemfiles/sidekiq_6.5.gemfile +0 -33
- data/lib/sidekiq/throttled/communicator/callbacks.rb +0 -72
- data/lib/sidekiq/throttled/communicator/exception_handler.rb +0 -25
- data/lib/sidekiq/throttled/communicator/listener.rb +0 -109
- data/lib/sidekiq/throttled/communicator.rb +0 -116
- data/lib/sidekiq/throttled/expirable_list.rb +0 -70
- data/lib/sidekiq/throttled/fetch/unit_of_work.rb +0 -83
- data/lib/sidekiq/throttled/patches/queue.rb +0 -18
- data/lib/sidekiq/throttled/queue_name.rb +0 -46
- data/lib/sidekiq/throttled/queues_pauser.rb +0 -152
- data/lib/sidekiq/throttled/testing.rb +0 -12
- data/lib/sidekiq/throttled/utils.rb +0 -19
- data/lib/sidekiq/throttled/web/queues.html.erb +0 -49
- data/lib/sidekiq/throttled/web/summary_fix.js +0 -10
- data/lib/sidekiq/throttled/web/summary_fix.rb +0 -35
- data/rubocop/layout.yml +0 -24
- data/rubocop/lint.yml +0 -41
- data/rubocop/metrics.yml +0 -4
- data/rubocop/performance.yml +0 -25
- data/rubocop/rspec.yml +0 -3
- data/rubocop/style.yml +0 -84
- data/sidekiq-throttled.gemspec +0 -36
- /data/{LICENSE.md → LICENSE} +0 -0
@@ -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,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,18 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Sidekiq
|
4
|
-
module Throttled
|
5
|
-
module Patches
|
6
|
-
module Queue
|
7
|
-
def paused?
|
8
|
-
QueuesPauser.instance.paused? name
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.apply!
|
12
|
-
require "sidekiq/api"
|
13
|
-
::Sidekiq::Queue.send(:prepend, self)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Sidekiq
|
4
|
-
module Throttled
|
5
|
-
# Queue name utility belt.
|
6
|
-
#
|
7
|
-
# @private
|
8
|
-
module QueueName
|
9
|
-
# RegExp used to stip out any redisr-namespace prefixes with `queue:`.
|
10
|
-
QUEUE_NAME_PREFIX_RE = %r{.*queue:}.freeze
|
11
|
-
private_constant :QUEUE_NAME_PREFIX_RE
|
12
|
-
|
13
|
-
class << self
|
14
|
-
# Strips redis-namespace and `queue:` prefix from given queue name.
|
15
|
-
#
|
16
|
-
# @example
|
17
|
-
#
|
18
|
-
# QueueName.normalize "queue:default"
|
19
|
-
# # => "default"
|
20
|
-
#
|
21
|
-
# QueueName.normalize "queue:queue:default"
|
22
|
-
# # => "default"
|
23
|
-
#
|
24
|
-
# QueueName.normalize "foo:bar:queue:default"
|
25
|
-
# # => "default"
|
26
|
-
#
|
27
|
-
# @param [#to_s]
|
28
|
-
# @return [String]
|
29
|
-
def normalize(queue)
|
30
|
-
-queue.to_s.sub(QUEUE_NAME_PREFIX_RE, "")
|
31
|
-
end
|
32
|
-
|
33
|
-
# Prepends `queue:` prefix to given `queue` name.
|
34
|
-
#
|
35
|
-
# @note It does not normalizes queue before expanding it, thus
|
36
|
-
# double-call of this method will potentially do some harm.
|
37
|
-
#
|
38
|
-
# @param [#to_s] queue Queue name
|
39
|
-
# @return [String]
|
40
|
-
def expand(queue)
|
41
|
-
-"queue:#{queue}"
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
@@ -1,152 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "set"
|
4
|
-
require "singleton"
|
5
|
-
require "concurrent/timer_task"
|
6
|
-
|
7
|
-
require "sidekiq/throttled/patches/queue"
|
8
|
-
require "sidekiq/throttled/communicator"
|
9
|
-
require "sidekiq/throttled/queue_name"
|
10
|
-
|
11
|
-
module Sidekiq
|
12
|
-
module Throttled
|
13
|
-
# Singleton class used to pause queues from being processed.
|
14
|
-
# For the sake of efficiency it uses {Communicator} behind the scene
|
15
|
-
# to notify all processes about paused/resumed queues.
|
16
|
-
#
|
17
|
-
# @private
|
18
|
-
class QueuesPauser
|
19
|
-
include Singleton
|
20
|
-
|
21
|
-
# Redis key of Set with paused queues.
|
22
|
-
#
|
23
|
-
# @return [String]
|
24
|
-
PAUSED_QUEUES = "throttled:X:paused_queues"
|
25
|
-
private_constant :PAUSED_QUEUES
|
26
|
-
|
27
|
-
# {Communicator} message used to notify that queue needs to be paused.
|
28
|
-
#
|
29
|
-
# @return [String]
|
30
|
-
PAUSE_MESSAGE = "pause"
|
31
|
-
private_constant :PAUSE_MESSAGE
|
32
|
-
|
33
|
-
# {Communicator} message used to notify that queue needs to be resumed.
|
34
|
-
#
|
35
|
-
# @return [String]
|
36
|
-
RESUME_MESSAGE = "resume"
|
37
|
-
private_constant :RESUME_MESSAGE
|
38
|
-
|
39
|
-
# Initializes singleton instance.
|
40
|
-
def initialize
|
41
|
-
@paused_queues = Set.new
|
42
|
-
@communicator = Communicator.instance
|
43
|
-
@mutex = Mutex.new
|
44
|
-
end
|
45
|
-
|
46
|
-
# Configures Sidekiq server to keep actual list of paused queues.
|
47
|
-
#
|
48
|
-
# @private
|
49
|
-
# @return [void]
|
50
|
-
def setup!
|
51
|
-
Patches::Queue.apply!
|
52
|
-
|
53
|
-
Sidekiq.configure_server do |config|
|
54
|
-
config.on(:startup) { start_watcher }
|
55
|
-
config.on(:quiet) { stop_watcher }
|
56
|
-
|
57
|
-
@communicator.receive(PAUSE_MESSAGE, &method(:add))
|
58
|
-
@communicator.receive(RESUME_MESSAGE, &method(:delete))
|
59
|
-
@communicator.ready { sync! }
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
# Returns queues list with paused queues being stripped out.
|
64
|
-
#
|
65
|
-
# @private
|
66
|
-
# @return [Array<String>]
|
67
|
-
def filter(queues)
|
68
|
-
@mutex.synchronize { queues - @paused_queues.to_a }
|
69
|
-
rescue => e
|
70
|
-
Sidekiq.logger.error { "[#{self.class}] Failed filter queues: #{e}" }
|
71
|
-
queues
|
72
|
-
end
|
73
|
-
|
74
|
-
# Returns list of paused queues.
|
75
|
-
#
|
76
|
-
# @return [Array<String>]
|
77
|
-
def paused_queues
|
78
|
-
Sidekiq.redis { |conn| conn.smembers(PAUSED_QUEUES).to_a }
|
79
|
-
end
|
80
|
-
|
81
|
-
# Pauses given `queue`.
|
82
|
-
#
|
83
|
-
# @param [#to_s] queue
|
84
|
-
# @return [void]
|
85
|
-
def pause!(queue)
|
86
|
-
queue = QueueName.normalize queue.to_s
|
87
|
-
|
88
|
-
Sidekiq.redis do |conn|
|
89
|
-
conn.sadd(PAUSED_QUEUES, queue)
|
90
|
-
@communicator.transmit(conn, PAUSE_MESSAGE, queue)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
# Checks if given `queue` is paused.
|
95
|
-
#
|
96
|
-
# @param queue [#to_s]
|
97
|
-
# @return [Boolean]
|
98
|
-
def paused?(queue)
|
99
|
-
queue = QueueName.normalize queue.to_s
|
100
|
-
Sidekiq.redis { |conn| conn.sismember(PAUSED_QUEUES, queue) }
|
101
|
-
end
|
102
|
-
|
103
|
-
# Resumes given `queue`.
|
104
|
-
#
|
105
|
-
# @param [#to_s] queue
|
106
|
-
# @return [void]
|
107
|
-
def resume!(queue)
|
108
|
-
queue = QueueName.normalize queue.to_s
|
109
|
-
|
110
|
-
Sidekiq.redis do |conn|
|
111
|
-
conn.srem(PAUSED_QUEUES, queue)
|
112
|
-
@communicator.transmit(conn, RESUME_MESSAGE, queue)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
private
|
117
|
-
|
118
|
-
def add(queue)
|
119
|
-
@mutex.synchronize do
|
120
|
-
@paused_queues << QueueName.expand(queue)
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
def delete(queue)
|
125
|
-
@mutex.synchronize do
|
126
|
-
@paused_queues.delete QueueName.expand(queue)
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
def sync!
|
131
|
-
@mutex.synchronize do
|
132
|
-
@paused_queues.replace(paused_queues.map { |q| QueueName.expand q })
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
def start_watcher
|
137
|
-
@mutex.synchronize do
|
138
|
-
@watcher ||= Concurrent::TimerTask.execute({
|
139
|
-
:run_now => true,
|
140
|
-
:execution_interval => 60
|
141
|
-
}) { sync! }
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
def stop_watcher
|
146
|
-
@mutex.synchronize do
|
147
|
-
defined?(@watcher) && @watcher&.shutdown
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
@@ -1,19 +0,0 @@
|
|
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(%r{^::}, "").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
|
@@ -1,49 +0,0 @@
|
|
1
|
-
<h3><%= t('Queues') %></h3>
|
2
|
-
|
3
|
-
<div class="table_container">
|
4
|
-
<table class="queues table table-hover table-bordered table-striped table-white">
|
5
|
-
<thead>
|
6
|
-
<th><%= t('Queue') %></th>
|
7
|
-
<th><%= t('Size') %></th>
|
8
|
-
<th><%= t('Actions') %></th>
|
9
|
-
</thead>
|
10
|
-
<% @queues.each do |queue| %>
|
11
|
-
<tr>
|
12
|
-
<td>
|
13
|
-
<a href="<%= root_path %>queues/<%= CGI.escape(queue.name) %>"><%= queue.name %></a>
|
14
|
-
</td>
|
15
|
-
<td><%= number_with_delimiter(queue.size) %> </td>
|
16
|
-
<td width="20%">
|
17
|
-
<form action="<%=root_path %>enhanced-queues/<%= CGI.escape(queue.name) %>" method="post" style="display:inline">
|
18
|
-
<%= csrf_tag %>
|
19
|
-
<% if queue.paused? %>
|
20
|
-
<button class="btn btn-primary btn-pauser-resume btn-xs" type="submit" name="action" value="resume">Resume</button>
|
21
|
-
<% else %>
|
22
|
-
<button class="btn btn-danger btn-pauser-pause btn-xs" type="submit" name="action" value="pause">Pause</button>
|
23
|
-
<% end %>
|
24
|
-
|
25
|
-
<button class="btn btn-danger btn-xs" type="submit" name="action" value="delete" data-confirm="<%= t('AreYouSureDeleteQueue', :queue => h(queue.name)) %>"><%= t('Delete') %></button>
|
26
|
-
</form>
|
27
|
-
</td>
|
28
|
-
</tr>
|
29
|
-
<% end %>
|
30
|
-
</table>
|
31
|
-
</div>
|
32
|
-
|
33
|
-
<style>
|
34
|
-
.btn-pauser-pause {
|
35
|
-
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #b13e00), color-stop(100%, #983500));
|
36
|
-
background-image: -webkit-linear-gradient(#b13e00, #983500);
|
37
|
-
background-image: -moz-linear-gradient(#b13e00, #983500);
|
38
|
-
background-image: -o-linear-gradient(#b13e00, #983500);
|
39
|
-
background-image: linear-gradient(#b13e00, #983500);
|
40
|
-
}
|
41
|
-
|
42
|
-
.btn-pauser-resume {
|
43
|
-
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #00b13e), color-stop(100%, #009835));
|
44
|
-
background-image: -webkit-linear-gradient(#00b13e, #009835);
|
45
|
-
background-image: -moz-linear-gradient(#00b13e, #009835);
|
46
|
-
background-image: -o-linear-gradient(#00b13e, #009835);
|
47
|
-
background-image: linear-gradient(#00b13e, #009835);
|
48
|
-
}
|
49
|
-
</style>
|
@@ -1,10 +0,0 @@
|
|
1
|
-
document.addEventListener("DOMContentLoaded", function () {
|
2
|
-
var elem = document.querySelector(".summary li.enqueued > a"), href;
|
3
|
-
|
4
|
-
if (!elem) {
|
5
|
-
console.warn("[Sidekiq::Threshold] cannot find summary bar link to fix");
|
6
|
-
} else {
|
7
|
-
href = elem.getAttribute("href").toString();
|
8
|
-
elem.setAttribute("href", href.replace(/\/queues$/, "/enhanced-queues"));
|
9
|
-
}
|
10
|
-
});
|
@@ -1,35 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Sidekiq
|
4
|
-
module Throttled
|
5
|
-
module Web
|
6
|
-
module SummaryFix
|
7
|
-
JAVASCRIPT = [File.read(File.expand_path("summary_fix.js", __dir__)).freeze].freeze
|
8
|
-
HEADERS = { "Content-Type" => "application/javascript" }.freeze
|
9
|
-
|
10
|
-
class << self
|
11
|
-
attr_accessor :enabled
|
12
|
-
|
13
|
-
def apply!(app)
|
14
|
-
Sidekiq::WebAction.prepend SummaryFix
|
15
|
-
|
16
|
-
app.get("/throttled/summary_fix") do
|
17
|
-
[200, HEADERS.dup, JAVASCRIPT.dup]
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def display_custom_head
|
23
|
-
"#{super}#{summary_fix_script if SummaryFix.enabled}"
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def summary_fix_script
|
29
|
-
src = "#{root_path}throttled/summary_fix"
|
30
|
-
%(<script type="text/javascript" src="#{src}"></script>)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
data/rubocop/layout.yml
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
Layout/ArgumentAlignment:
|
2
|
-
EnforcedStyle: with_fixed_indentation
|
3
|
-
|
4
|
-
Layout/EmptyLinesAroundAttributeAccessor:
|
5
|
-
Enabled: true
|
6
|
-
|
7
|
-
Layout/FirstArrayElementIndentation:
|
8
|
-
EnforcedStyle: consistent
|
9
|
-
|
10
|
-
Layout/FirstHashElementIndentation:
|
11
|
-
Enabled: true
|
12
|
-
EnforcedStyle: consistent
|
13
|
-
|
14
|
-
Layout/HashAlignment:
|
15
|
-
Enabled: true
|
16
|
-
EnforcedHashRocketStyle: table
|
17
|
-
EnforcedColonStyle: table
|
18
|
-
|
19
|
-
Layout/SpaceAroundMethodCallOperator:
|
20
|
-
Enabled: true
|
21
|
-
|
22
|
-
Layout/MultilineMethodCallIndentation:
|
23
|
-
Enabled: true
|
24
|
-
EnforcedStyle: indented
|
data/rubocop/lint.yml
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
Lint/BinaryOperatorWithIdenticalOperands:
|
2
|
-
Enabled: true
|
3
|
-
|
4
|
-
Lint/DeprecatedOpenSSLConstant:
|
5
|
-
Enabled: true
|
6
|
-
|
7
|
-
Lint/DuplicateElsifCondition:
|
8
|
-
Enabled: true
|
9
|
-
|
10
|
-
Lint/DuplicateRescueException:
|
11
|
-
Enabled: true
|
12
|
-
|
13
|
-
Lint/EmptyConditionalBody:
|
14
|
-
Enabled: true
|
15
|
-
|
16
|
-
Lint/FloatComparison:
|
17
|
-
Enabled: true
|
18
|
-
|
19
|
-
Lint/MissingSuper:
|
20
|
-
Enabled: true
|
21
|
-
|
22
|
-
Lint/MixedRegexpCaptureTypes:
|
23
|
-
Enabled: true
|
24
|
-
|
25
|
-
Lint/OutOfRangeRegexpRef:
|
26
|
-
Enabled: true
|
27
|
-
|
28
|
-
Lint/RaiseException:
|
29
|
-
Enabled: true
|
30
|
-
|
31
|
-
Lint/SelfAssignment:
|
32
|
-
Enabled: true
|
33
|
-
|
34
|
-
Lint/StructNewOverride:
|
35
|
-
Enabled: true
|
36
|
-
|
37
|
-
Lint/TopLevelReturnWithArgument:
|
38
|
-
Enabled: true
|
39
|
-
|
40
|
-
Lint/UnreachableLoop:
|
41
|
-
Enabled: true
|
data/rubocop/metrics.yml
DELETED