sidekiq 5.2.2 → 5.2.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sidekiq might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Changes.md +11 -0
- data/Ent-Changes.md +3 -0
- data/Pro-Changes.md +5 -0
- data/bin/sidekiqctl +141 -3
- data/lib/sidekiq/job_logger.rb +2 -2
- data/lib/sidekiq/job_retry.rb +15 -5
- data/lib/sidekiq/launcher.rb +1 -1
- data/lib/sidekiq/manager.rb +3 -3
- data/lib/sidekiq/processor.rb +2 -2
- data/lib/sidekiq/redis_connection.rb +19 -0
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/worker.rb +14 -3
- data/web/assets/javascripts/dashboard.js +15 -5
- data/web/assets/stylesheets/application.css +35 -2
- data/web/views/_nav.erb +3 -17
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f67e98eb8e3fff8ee4d57f08d5668e41b320fa4
|
4
|
+
data.tar.gz: a11f770fd95fd45b3c0be43beee5c83417811fd4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e6739681028126924c049e41bbfcdc92bea0d1ee4fb965f4e332da4cca9f10352f5cf18e05345a843d19b6111510f55c88aa97f4e21585bf66b479b7ae2f9bc
|
7
|
+
data.tar.gz: 07f0432c69395be2933f152acb09c8fa4fe43be104011df237b0b4db56073b4725eb3fa3073872376f09d072ea15608f79a32b3dc28104ba18665082ad64adf4
|
data/Changes.md
CHANGED
@@ -2,6 +2,17 @@
|
|
2
2
|
|
3
3
|
[Sidekiq Changes](https://github.com/mperham/sidekiq/blob/master/Changes.md) | [Sidekiq Pro Changes](https://github.com/mperham/sidekiq/blob/master/Pro-Changes.md) | [Sidekiq Enterprise Changes](https://github.com/mperham/sidekiq/blob/master/Ent-Changes.md)
|
4
4
|
|
5
|
+
5.2.3
|
6
|
+
---------
|
7
|
+
|
8
|
+
- Warning message on invalid REDIS\_PROVIDER [#3970]
|
9
|
+
- Add `sidekiqctl status` command [#4003, dzunk]
|
10
|
+
- Update elapsed time calculatons to use monotonic clock [#3999]
|
11
|
+
- Fix a few issues with mobile Web UI styling [#3973, navied]
|
12
|
+
- Jobs with `retry: false` now go through the global `death_handlers`,
|
13
|
+
meaning you can take action on failed ephemeral jobs. [#3980, Benjamin-Dobell]
|
14
|
+
- Fix race condition in defining Workers. [#3997, mattbooks]
|
15
|
+
|
5
16
|
5.2.2
|
6
17
|
---------
|
7
18
|
|
data/Ent-Changes.md
CHANGED
@@ -7,6 +7,9 @@ Please see [http://sidekiq.org/](http://sidekiq.org/) for more details and how t
|
|
7
7
|
HEAD
|
8
8
|
-------------
|
9
9
|
|
10
|
+
- Fix elapsed time calculations to use monotonic clock [#4000, sj26]
|
11
|
+
- Fix edge case where flapping leadership would cause old periodic
|
12
|
+
jobs to be fired once [#3974]
|
10
13
|
- Add support for sidekiqswarm memory monitoring on FreeBSD [#3884]
|
11
14
|
|
12
15
|
1.7.1
|
data/Pro-Changes.md
CHANGED
@@ -4,6 +4,11 @@
|
|
4
4
|
|
5
5
|
Please see [http://sidekiq.org/](http://sidekiq.org/) for more details and how to buy.
|
6
6
|
|
7
|
+
HEAD
|
8
|
+
---------
|
9
|
+
|
10
|
+
- Add Japanese and Russian translations, see [issue #3951](https://github.com/mperham/sidekiq/issues/3951) to add your own language
|
11
|
+
|
7
12
|
4.0.4
|
8
13
|
---------
|
9
14
|
|
data/bin/sidekiqctl
CHANGED
@@ -1,20 +1,27 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'fileutils'
|
4
|
+
require 'sidekiq/api'
|
4
5
|
|
5
6
|
class Sidekiqctl
|
6
7
|
DEFAULT_KILL_TIMEOUT = 10
|
8
|
+
CMD = File.basename($0)
|
7
9
|
|
8
10
|
attr_reader :stage, :pidfile, :kill_timeout
|
9
11
|
|
10
12
|
def self.print_usage
|
11
|
-
puts "#{
|
13
|
+
puts "#{CMD} - control Sidekiq from the command line."
|
14
|
+
puts
|
15
|
+
puts "Usage: #{CMD} quiet <pidfile> <kill_timeout>"
|
16
|
+
puts " #{CMD} stop <pidfile> <kill_timeout>"
|
17
|
+
puts " #{CMD} status <section>"
|
12
18
|
puts
|
13
|
-
puts "Usage: #{File.basename($0)} <command> <pidfile> <kill_timeout>"
|
14
|
-
puts " where <command> is either 'quiet' or 'stop'"
|
15
19
|
puts " <pidfile> is path to a pidfile"
|
16
20
|
puts " <kill_timeout> is number of seconds to wait until Sidekiq exits"
|
17
21
|
puts " (default: #{Sidekiqctl::DEFAULT_KILL_TIMEOUT}), after which Sidekiq will be KILL'd"
|
22
|
+
puts
|
23
|
+
puts " <section> (optional) view a specific section of the status output"
|
24
|
+
puts " Valid sections are: #{Sidekiqctl::Status::VALID_SECTIONS.join(', ')}"
|
18
25
|
puts
|
19
26
|
puts "Be sure to set the kill_timeout LONGER than Sidekiq's -t timeout. If you want"
|
20
27
|
puts "to wait 60 seconds for jobs to finish, use `sidekiq -t 60` and `sidekiqctl stop"
|
@@ -85,6 +92,137 @@ class Sidekiqctl
|
|
85
92
|
done 'Sidekiq shut down forcefully.'
|
86
93
|
end
|
87
94
|
alias_method :shutdown, :stop
|
95
|
+
|
96
|
+
class Status
|
97
|
+
VALID_SECTIONS = %w[all version overview processes queues]
|
98
|
+
def display(section = nil)
|
99
|
+
section ||= 'all'
|
100
|
+
unless VALID_SECTIONS.include? section
|
101
|
+
puts "I don't know how to check the status of '#{section}'!"
|
102
|
+
puts "Try one of these: #{VALID_SECTIONS.join(', ')}"
|
103
|
+
return
|
104
|
+
end
|
105
|
+
send(section)
|
106
|
+
rescue StandardError => e
|
107
|
+
puts "Couldn't get status: #{e}"
|
108
|
+
end
|
109
|
+
|
110
|
+
def all
|
111
|
+
version
|
112
|
+
puts
|
113
|
+
overview
|
114
|
+
puts
|
115
|
+
processes
|
116
|
+
puts
|
117
|
+
queues
|
118
|
+
end
|
119
|
+
|
120
|
+
def version
|
121
|
+
puts "Sidekiq #{Sidekiq::VERSION}"
|
122
|
+
puts Time.now
|
123
|
+
end
|
124
|
+
|
125
|
+
def overview
|
126
|
+
puts '---- Overview ----'
|
127
|
+
puts " Processed: #{delimit stats.processed}"
|
128
|
+
puts " Failed: #{delimit stats.failed}"
|
129
|
+
puts " Busy: #{delimit stats.workers_size}"
|
130
|
+
puts " Enqueued: #{delimit stats.enqueued}"
|
131
|
+
puts " Retries: #{delimit stats.retry_size}"
|
132
|
+
puts " Scheduled: #{delimit stats.scheduled_size}"
|
133
|
+
puts " Dead: #{delimit stats.dead_size}"
|
134
|
+
end
|
135
|
+
|
136
|
+
def processes
|
137
|
+
puts "---- Processes (#{process_set.size}) ----"
|
138
|
+
process_set.each_with_index do |process, index|
|
139
|
+
puts "#{process['identity']} #{tags_for(process)}"
|
140
|
+
puts " Started: #{Time.at(process['started_at'])} (#{time_ago(process['started_at'])})"
|
141
|
+
puts " Threads: #{process['concurrency']} (#{process['busy']} busy)"
|
142
|
+
puts " Queues: #{split_multiline(process['queues'].sort, pad: 11)}"
|
143
|
+
puts '' unless (index+1) == process_set.size
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
COL_PAD = 2
|
148
|
+
def queues
|
149
|
+
puts "---- Queues (#{queue_data.size}) ----"
|
150
|
+
columns = {
|
151
|
+
name: [:ljust, (['name'] + queue_data.map(&:name)).map(&:length).max + COL_PAD],
|
152
|
+
size: [:rjust, (['size'] + queue_data.map(&:size)).map(&:length).max + COL_PAD],
|
153
|
+
latency: [:rjust, (['latency'] + queue_data.map(&:latency)).map(&:length).max + COL_PAD]
|
154
|
+
}
|
155
|
+
columns.each { |col, (dir, width)| print col.to_s.upcase.public_send(dir, width) }
|
156
|
+
puts
|
157
|
+
queue_data.each do |q|
|
158
|
+
columns.each do |col, (dir, width)|
|
159
|
+
print q.send(col).public_send(dir, width)
|
160
|
+
end
|
161
|
+
puts
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
private
|
166
|
+
|
167
|
+
def delimit(number)
|
168
|
+
number.to_s.reverse.scan(/.{1,3}/).join(',').reverse
|
169
|
+
end
|
170
|
+
|
171
|
+
def split_multiline(values, opts = {})
|
172
|
+
return 'none' unless values
|
173
|
+
pad = opts[:pad] || 0
|
174
|
+
max_length = opts[:max_length] || (80 - pad)
|
175
|
+
out = []
|
176
|
+
line = ''
|
177
|
+
values.each do |value|
|
178
|
+
if (line.length + value.length) > max_length
|
179
|
+
out << line
|
180
|
+
line = ' ' * pad
|
181
|
+
end
|
182
|
+
line << value + ', '
|
183
|
+
end
|
184
|
+
out << line[0..-3]
|
185
|
+
out.join("\n")
|
186
|
+
end
|
187
|
+
|
188
|
+
def tags_for(process)
|
189
|
+
tags = [
|
190
|
+
process['tag'],
|
191
|
+
process['labels'],
|
192
|
+
(process['quiet'] == 'true' ? 'quiet' : nil)
|
193
|
+
].flatten.compact
|
194
|
+
tags.any? ? "[#{tags.join('] [')}]" : nil
|
195
|
+
end
|
196
|
+
|
197
|
+
def time_ago(timestamp)
|
198
|
+
seconds = Time.now - Time.at(timestamp)
|
199
|
+
return 'just now' if seconds < 60
|
200
|
+
return 'a minute ago' if seconds < 120
|
201
|
+
return "#{seconds.floor / 60} minutes ago" if seconds < 3600
|
202
|
+
return 'an hour ago' if seconds < 7200
|
203
|
+
"#{seconds.floor / 60 / 60} hours ago"
|
204
|
+
end
|
205
|
+
|
206
|
+
QUEUE_STRUCT = Struct.new(:name, :size, :latency)
|
207
|
+
def queue_data
|
208
|
+
@queue_data ||= Sidekiq::Queue.all.map do |q|
|
209
|
+
QUEUE_STRUCT.new(q.name, q.size.to_s, sprintf('%#.2f', q.latency))
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def process_set
|
214
|
+
@process_set ||= Sidekiq::ProcessSet.new
|
215
|
+
end
|
216
|
+
|
217
|
+
def stats
|
218
|
+
@stats ||= Sidekiq::Stats.new
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
if ARGV[0] == 'status'
|
224
|
+
Sidekiqctl::Status.new.display(ARGV[1])
|
225
|
+
exit
|
88
226
|
end
|
89
227
|
|
90
228
|
if ARGV.length < 2
|
data/lib/sidekiq/job_logger.rb
CHANGED
@@ -3,7 +3,7 @@ module Sidekiq
|
|
3
3
|
class JobLogger
|
4
4
|
|
5
5
|
def call(item, queue)
|
6
|
-
start =
|
6
|
+
start = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
7
7
|
logger.info("start")
|
8
8
|
yield
|
9
9
|
logger.info("done: #{elapsed(start)} sec")
|
@@ -15,7 +15,7 @@ module Sidekiq
|
|
15
15
|
private
|
16
16
|
|
17
17
|
def elapsed(start)
|
18
|
-
(
|
18
|
+
(::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - start).round(3)
|
19
19
|
end
|
20
20
|
|
21
21
|
def logger
|
data/lib/sidekiq/job_retry.rb
CHANGED
@@ -80,8 +80,18 @@ module Sidekiq
|
|
80
80
|
# ignore, will be pushed back onto queue during hard_shutdown
|
81
81
|
raise Sidekiq::Shutdown if exception_caused_by_shutdown?(e)
|
82
82
|
|
83
|
-
|
84
|
-
|
83
|
+
if msg['retry']
|
84
|
+
attempt_retry(nil, msg, queue, e)
|
85
|
+
else
|
86
|
+
Sidekiq.death_handlers.each do |handler|
|
87
|
+
begin
|
88
|
+
handler.call(msg, e)
|
89
|
+
rescue => handler_ex
|
90
|
+
handle_exception(handler_ex, { context: "Error calling death handler", job: msg })
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
85
95
|
raise e
|
86
96
|
end
|
87
97
|
|
@@ -158,7 +168,8 @@ module Sidekiq
|
|
158
168
|
|
159
169
|
if count < max_retry_attempts
|
160
170
|
delay = delay_for(worker, count, exception)
|
161
|
-
|
171
|
+
# Logging here can break retries if the logging device raises ENOSPC #3979
|
172
|
+
#logger.debug { "Failure! Retry #{count} in #{delay} seconds" }
|
162
173
|
retry_at = Time.now.to_f + delay
|
163
174
|
payload = Sidekiq.dump_json(msg)
|
164
175
|
Sidekiq.redis do |conn|
|
@@ -171,7 +182,6 @@ module Sidekiq
|
|
171
182
|
end
|
172
183
|
|
173
184
|
def retries_exhausted(worker, msg, exception)
|
174
|
-
logger.debug { "Retries exhausted for job" }
|
175
185
|
begin
|
176
186
|
block = worker && worker.sidekiq_retries_exhausted_block
|
177
187
|
block.call(msg, exception) if block
|
@@ -191,7 +201,7 @@ module Sidekiq
|
|
191
201
|
end
|
192
202
|
|
193
203
|
def send_to_morgue(msg)
|
194
|
-
|
204
|
+
logger.info { "Adding dead #{msg['class']} job #{msg['jid']}" }
|
195
205
|
payload = Sidekiq.dump_json(msg)
|
196
206
|
DeadSet.new.kill(payload, notify_failure: false)
|
197
207
|
end
|
data/lib/sidekiq/launcher.rb
CHANGED
@@ -40,7 +40,7 @@ module Sidekiq
|
|
40
40
|
# return until all work is complete and cleaned up.
|
41
41
|
# It can take up to the timeout to complete.
|
42
42
|
def stop
|
43
|
-
deadline =
|
43
|
+
deadline = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) + @options[:timeout]
|
44
44
|
|
45
45
|
@done = true
|
46
46
|
@manager.quiet
|
data/lib/sidekiq/manager.rb
CHANGED
@@ -30,7 +30,7 @@ module Sidekiq
|
|
30
30
|
def initialize(options={})
|
31
31
|
logger.debug { options.inspect }
|
32
32
|
@options = options
|
33
|
-
@count = options[:concurrency] ||
|
33
|
+
@count = options[:concurrency] || 10
|
34
34
|
raise ArgumentError, "Concurrency of #{@count} is not supported" if @count < 1
|
35
35
|
|
36
36
|
@done = false
|
@@ -70,11 +70,11 @@ module Sidekiq
|
|
70
70
|
return if @workers.empty?
|
71
71
|
|
72
72
|
logger.info { "Pausing to allow workers to finish..." }
|
73
|
-
remaining = deadline -
|
73
|
+
remaining = deadline - ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
74
74
|
while remaining > PAUSE_TIME
|
75
75
|
return if @workers.empty?
|
76
76
|
sleep PAUSE_TIME
|
77
|
-
remaining = deadline -
|
77
|
+
remaining = deadline - ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
78
78
|
end
|
79
79
|
return if @workers.empty?
|
80
80
|
|
data/lib/sidekiq/processor.rb
CHANGED
@@ -87,7 +87,7 @@ module Sidekiq
|
|
87
87
|
def get_one
|
88
88
|
begin
|
89
89
|
work = @strategy.retrieve_work
|
90
|
-
(logger.info { "Redis is online, #{
|
90
|
+
(logger.info { "Redis is online, #{::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - @down} sec downtime" }; @down = nil) if @down
|
91
91
|
work
|
92
92
|
rescue Sidekiq::Shutdown
|
93
93
|
rescue => ex
|
@@ -107,7 +107,7 @@ module Sidekiq
|
|
107
107
|
|
108
108
|
def handle_fetch_exception(ex)
|
109
109
|
if !@down
|
110
|
-
@down =
|
110
|
+
@down = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
111
111
|
logger.error("Error fetching job: #{ex}")
|
112
112
|
handle_exception(ex)
|
113
113
|
end
|
@@ -115,6 +115,25 @@ module Sidekiq
|
|
115
115
|
# REDIS_PROVIDER=MY_REDIS_URL
|
116
116
|
# and Sidekiq will find your custom URL variable with no custom
|
117
117
|
# initialization code at all.
|
118
|
+
p = ENV['REDIS_PROVIDER']
|
119
|
+
if p && p =~ /\:/
|
120
|
+
Sidekiq.logger.error <<-EOM
|
121
|
+
|
122
|
+
#################################################################################
|
123
|
+
|
124
|
+
REDIS_PROVIDER should be set to the **name** of the variable which contains the Redis URL, not a URL itself.
|
125
|
+
Platforms like Heroku sell addons that publish a *_URL variable. You tell Sidekiq with REDIS_PROVIDER, e.g.:
|
126
|
+
|
127
|
+
REDIS_PROVIDER=REDISTOGO_URL
|
128
|
+
REDISTOGO_URL=redis://somehost.example.com:6379/4
|
129
|
+
|
130
|
+
Use REDIS_URL if you wish to point Sidekiq to a URL directly.
|
131
|
+
|
132
|
+
This configuration error will crash starting in Sidekiq 5.3.
|
133
|
+
|
134
|
+
#################################################################################
|
135
|
+
EOM
|
136
|
+
end
|
118
137
|
ENV[
|
119
138
|
ENV['REDIS_PROVIDER'] || 'REDIS_URL'
|
120
139
|
]
|
data/lib/sidekiq/version.rb
CHANGED
data/lib/sidekiq/worker.rb
CHANGED
@@ -66,6 +66,7 @@ module Sidekiq
|
|
66
66
|
end
|
67
67
|
|
68
68
|
module ClassMethods
|
69
|
+
ACCESSOR_MUTEX = Mutex.new
|
69
70
|
|
70
71
|
def delay(*args)
|
71
72
|
raise ArgumentError, "Do not call .delay on a Sidekiq::Worker class, call .perform_async"
|
@@ -148,10 +149,18 @@ module Sidekiq
|
|
148
149
|
instance_writer = true
|
149
150
|
|
150
151
|
attrs.each do |name|
|
152
|
+
synchronized_getter = "__synchronized_#{name}"
|
153
|
+
|
151
154
|
singleton_class.instance_eval do
|
152
155
|
undef_method(name) if method_defined?(name) || private_method_defined?(name)
|
153
156
|
end
|
154
|
-
|
157
|
+
|
158
|
+
define_singleton_method(synchronized_getter) { nil }
|
159
|
+
singleton_class.class_eval do
|
160
|
+
private(synchronized_getter)
|
161
|
+
end
|
162
|
+
|
163
|
+
define_singleton_method(name) { ACCESSOR_MUTEX.synchronize { send synchronized_getter } }
|
155
164
|
|
156
165
|
ivar = "@#{name}"
|
157
166
|
|
@@ -161,8 +170,10 @@ module Sidekiq
|
|
161
170
|
end
|
162
171
|
define_singleton_method("#{name}=") do |val|
|
163
172
|
singleton_class.class_eval do
|
164
|
-
|
165
|
-
|
173
|
+
ACCESSOR_MUTEX.synchronize do
|
174
|
+
undef_method(synchronized_getter) if method_defined?(synchronized_getter) || private_method_defined?(synchronized_getter)
|
175
|
+
define_method(synchronized_getter) { val }
|
176
|
+
end
|
166
177
|
end
|
167
178
|
|
168
179
|
if singleton_class?
|
@@ -298,8 +298,18 @@ var debounce = function(fn, timeout)
|
|
298
298
|
}
|
299
299
|
};
|
300
300
|
|
301
|
-
window.onresize =
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
301
|
+
window.onresize = function() {
|
302
|
+
var prevWidth = window.innerWidth;
|
303
|
+
|
304
|
+
return debounce(function () {
|
305
|
+
var currWidth = window.innerWidth;
|
306
|
+
|
307
|
+
if (prevWidth !== currWidth) {
|
308
|
+
prevWidth = currWidth;
|
309
|
+
|
310
|
+
clearInterval(poller);
|
311
|
+
resetGraphs();
|
312
|
+
renderGraphs();
|
313
|
+
}
|
314
|
+
}, 125);
|
315
|
+
}();
|
@@ -126,7 +126,7 @@ header.row .pagination {
|
|
126
126
|
text-align: center;
|
127
127
|
width: 14%;
|
128
128
|
}
|
129
|
-
@media (max-width: 767px) and (min-width:
|
129
|
+
@media (max-width: 767px) and (min-width: 200px) {
|
130
130
|
.summary_bar ul li {
|
131
131
|
width: 100%;
|
132
132
|
}
|
@@ -219,6 +219,29 @@ table .table-checkbox label {
|
|
219
219
|
color: #585454;
|
220
220
|
}
|
221
221
|
|
222
|
+
|
223
|
+
.nav.navbar-nav{
|
224
|
+
display: flex;
|
225
|
+
width: 100%;
|
226
|
+
}
|
227
|
+
|
228
|
+
.navbar-livereload{
|
229
|
+
margin-left: auto;
|
230
|
+
white-space: nowrap;
|
231
|
+
}
|
232
|
+
|
233
|
+
.navbar-livereload .poll-wrapper a:last-child{
|
234
|
+
margin-left: 8px;
|
235
|
+
}
|
236
|
+
|
237
|
+
.navbar-right{
|
238
|
+
margin-right: 0;
|
239
|
+
}
|
240
|
+
|
241
|
+
.navbar-collapse.collapse{
|
242
|
+
overflow-x: auto !important;
|
243
|
+
}
|
244
|
+
|
222
245
|
@media (max-width: 768px) {
|
223
246
|
.navbar .navbar-header .navbar-livereload {
|
224
247
|
border: none;
|
@@ -234,13 +257,19 @@ table .table-checkbox label {
|
|
234
257
|
display: none;
|
235
258
|
}
|
236
259
|
|
260
|
+
.nav.navbar-nav{
|
261
|
+
display: block;
|
262
|
+
width: auto;
|
263
|
+
}
|
264
|
+
|
237
265
|
.navbar.navbar-fixed-top ul {
|
238
266
|
margin-right: -15px!important;
|
239
267
|
}
|
240
268
|
|
241
269
|
.navbar .nav a {
|
242
270
|
text-align: center;
|
243
|
-
}
|
271
|
+
}
|
272
|
+
|
244
273
|
}
|
245
274
|
|
246
275
|
@media (width: 768px) {
|
@@ -645,6 +674,10 @@ div.interval-slider input {
|
|
645
674
|
margin-right: 0;
|
646
675
|
}
|
647
676
|
|
677
|
+
.navbar #navbar-menu{
|
678
|
+
display: none;
|
679
|
+
}
|
680
|
+
|
648
681
|
.poll-wrapper {
|
649
682
|
width: 100%;
|
650
683
|
text-align: center;
|
data/web/views/_nav.erb
CHANGED
@@ -9,7 +9,7 @@
|
|
9
9
|
<div class="navbar-toggle collapsed navbar-livereload">
|
10
10
|
<%= erb :_poll_link %>
|
11
11
|
<% if Sidekiq::Web.app_url %>
|
12
|
-
<a class="btn btn-inverse" href="<%= Sidekiq::Web.app_url %>"
|
12
|
+
<a class="btn btn-inverse" href="<%= Sidekiq::Web.app_url %>"><%= t('BackToApp') %></a>
|
13
13
|
<% end %>
|
14
14
|
</div>
|
15
15
|
<a class="navbar-brand" href="<%= root_path %>">
|
@@ -32,27 +32,13 @@
|
|
32
32
|
<% end %>
|
33
33
|
<% end %>
|
34
34
|
|
35
|
-
<li class="dropdown" data-navbar="dropdown">
|
36
|
-
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
|
37
|
-
<%= t('Plugins') %> <span class="caret"></span>
|
38
|
-
</a>
|
39
|
-
<ul class="dropdown-menu" role="menu">
|
40
|
-
<% Sidekiq::Web.custom_tabs.each do |title, url| %>
|
41
|
-
<li>
|
42
|
-
<a href="<%= root_path %><%= url %>"><%= t(title) %></a>
|
43
|
-
</li>
|
44
|
-
<% end %>
|
45
|
-
</ul>
|
46
|
-
</li>
|
47
|
-
|
48
35
|
<% Sidekiq::Web.custom_tabs.each do |title, url| %>
|
49
36
|
<li class="<%= current_path.start_with?(url) ? 'active' : '' %>" data-navbar="custom-tab">
|
50
37
|
<a href="<%= root_path %><%= url %>"><%= t(title) %></a>
|
51
38
|
</li>
|
52
39
|
<% end %>
|
53
|
-
|
54
|
-
|
55
|
-
<li>
|
40
|
+
|
41
|
+
<li class="navbar-livereload">
|
56
42
|
<div class="poll-wrapper">
|
57
43
|
<%= erb :_poll_link %>
|
58
44
|
<% if Sidekiq::Web.app_url %>
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidekiq
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.2.
|
4
|
+
version: 5.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Perham
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-11-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|