sidekiq 7.1.2 → 7.2.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.
Potentially problematic release.
This version of sidekiq might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Changes.md +69 -0
- data/README.md +2 -2
- data/lib/sidekiq/api.rb +3 -3
- data/lib/sidekiq/client.rb +6 -3
- data/lib/sidekiq/config.rb +13 -4
- data/lib/sidekiq/deploy.rb +1 -1
- data/lib/sidekiq/job_retry.rb +19 -3
- data/lib/sidekiq/job_util.rb +2 -0
- data/lib/sidekiq/metrics/query.rb +3 -1
- data/lib/sidekiq/metrics/shared.rb +1 -1
- data/lib/sidekiq/paginator.rb +2 -2
- data/lib/sidekiq/processor.rb +27 -26
- data/lib/sidekiq/rails.rb +10 -15
- data/lib/sidekiq/redis_client_adapter.rb +17 -2
- data/lib/sidekiq/redis_connection.rb +1 -0
- data/lib/sidekiq/scheduled.rb +1 -1
- data/lib/sidekiq/testing.rb +25 -6
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web/action.rb +3 -3
- data/lib/sidekiq/web/application.rb +72 -6
- data/lib/sidekiq/web/csrf_protection.rb +1 -1
- data/lib/sidekiq/web/helpers.rb +31 -23
- data/lib/sidekiq/web.rb +13 -1
- data/web/assets/javascripts/application.js +16 -0
- data/web/assets/javascripts/dashboard-charts.js +17 -1
- data/web/assets/javascripts/dashboard.js +7 -9
- data/web/assets/javascripts/metrics.js +34 -0
- data/web/assets/stylesheets/application.css +9 -0
- data/web/locales/en.yml +2 -0
- data/web/locales/pt-br.yml +20 -0
- data/web/views/_job_info.erb +1 -1
- data/web/views/_metrics_period_select.erb +1 -1
- data/web/views/_summary.erb +7 -7
- data/web/views/busy.erb +3 -3
- data/web/views/dashboard.erb +23 -33
- data/web/views/filtering.erb +7 -0
- data/web/views/metrics.erb +36 -27
- data/web/views/metrics_for_job.erb +26 -35
- data/web/views/queues.erb +6 -2
- metadata +4 -3
@@ -15,7 +15,7 @@ module Sidekiq
|
|
15
15
|
"manifest-src 'self'",
|
16
16
|
"media-src 'self'",
|
17
17
|
"object-src 'none'",
|
18
|
-
"script-src 'self' https: http:
|
18
|
+
"script-src 'self' https: http:",
|
19
19
|
"style-src 'self' https: http: 'unsafe-inline'",
|
20
20
|
"worker-src 'self'",
|
21
21
|
"base-uri 'self'"
|
@@ -328,9 +328,75 @@ module Sidekiq
|
|
328
328
|
json Sidekiq::Stats.new.queues
|
329
329
|
end
|
330
330
|
|
331
|
+
########
|
332
|
+
# Filtering
|
333
|
+
|
334
|
+
get "/filter/metrics" do
|
335
|
+
redirect "#{root_path}metrics"
|
336
|
+
end
|
337
|
+
|
338
|
+
post "/filter/metrics" do
|
339
|
+
x = params[:substr]
|
340
|
+
q = Sidekiq::Metrics::Query.new
|
341
|
+
@period = h((params[:period] || "")[0..1])
|
342
|
+
@periods = METRICS_PERIODS
|
343
|
+
minutes = @periods.fetch(@period, @periods.values.first)
|
344
|
+
@query_result = q.top_jobs(minutes: minutes, class_filter: Regexp.new(Regexp.escape(x), Regexp::IGNORECASE))
|
345
|
+
|
346
|
+
erb :metrics
|
347
|
+
end
|
348
|
+
|
349
|
+
get "/filter/retries" do
|
350
|
+
x = params[:substr]
|
351
|
+
return redirect "#{root_path}retries" unless x && x != ""
|
352
|
+
|
353
|
+
@retries = search(Sidekiq::RetrySet.new, params[:substr])
|
354
|
+
erb :retries
|
355
|
+
end
|
356
|
+
|
357
|
+
post "/filter/retries" do
|
358
|
+
x = params[:substr]
|
359
|
+
return redirect "#{root_path}retries" unless x && x != ""
|
360
|
+
|
361
|
+
@retries = search(Sidekiq::RetrySet.new, params[:substr])
|
362
|
+
erb :retries
|
363
|
+
end
|
364
|
+
|
365
|
+
get "/filter/scheduled" do
|
366
|
+
x = params[:substr]
|
367
|
+
return redirect "#{root_path}scheduled" unless x && x != ""
|
368
|
+
|
369
|
+
@scheduled = search(Sidekiq::ScheduledSet.new, params[:substr])
|
370
|
+
erb :scheduled
|
371
|
+
end
|
372
|
+
|
373
|
+
post "/filter/scheduled" do
|
374
|
+
x = params[:substr]
|
375
|
+
return redirect "#{root_path}scheduled" unless x && x != ""
|
376
|
+
|
377
|
+
@scheduled = search(Sidekiq::ScheduledSet.new, params[:substr])
|
378
|
+
erb :scheduled
|
379
|
+
end
|
380
|
+
|
381
|
+
get "/filter/dead" do
|
382
|
+
x = params[:substr]
|
383
|
+
return redirect "#{root_path}morgue" unless x && x != ""
|
384
|
+
|
385
|
+
@dead = search(Sidekiq::DeadSet.new, params[:substr])
|
386
|
+
erb :morgue
|
387
|
+
end
|
388
|
+
|
389
|
+
post "/filter/dead" do
|
390
|
+
x = params[:substr]
|
391
|
+
return redirect "#{root_path}morgue" unless x && x != ""
|
392
|
+
|
393
|
+
@dead = search(Sidekiq::DeadSet.new, params[:substr])
|
394
|
+
erb :morgue
|
395
|
+
end
|
396
|
+
|
331
397
|
def call(env)
|
332
398
|
action = self.class.match(env)
|
333
|
-
return [404, {
|
399
|
+
return [404, {Rack::CONTENT_TYPE => "text/plain", Web::X_CASCADE => "pass"}, ["Not Found"]] unless action
|
334
400
|
|
335
401
|
app = @klass
|
336
402
|
resp = catch(:halt) do
|
@@ -347,10 +413,10 @@ module Sidekiq
|
|
347
413
|
else
|
348
414
|
# rendered content goes here
|
349
415
|
headers = {
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
416
|
+
Rack::CONTENT_TYPE => "text/html",
|
417
|
+
Rack::CACHE_CONTROL => "private, no-store",
|
418
|
+
Web::CONTENT_LANGUAGE => action.locale,
|
419
|
+
Web::CONTENT_SECURITY_POLICY => CSP_HEADER
|
354
420
|
}
|
355
421
|
# we'll let Rack calculate Content-Length for us.
|
356
422
|
[200, headers, [resp]]
|
data/lib/sidekiq/web/helpers.rb
CHANGED
@@ -21,6 +21,10 @@ module Sidekiq
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
+
def to_json(x)
|
25
|
+
Sidekiq.dump_json(x)
|
26
|
+
end
|
27
|
+
|
24
28
|
def singularize(str, count)
|
25
29
|
if count == 1 && str.respond_to?(:singularize) # rails
|
26
30
|
str.singularize
|
@@ -49,8 +53,29 @@ module Sidekiq
|
|
49
53
|
locale_files.select { |file| file =~ /\/#{lang}\.yml$/ }
|
50
54
|
end
|
51
55
|
|
52
|
-
|
53
|
-
|
56
|
+
def search(jobset, substr)
|
57
|
+
resultset = jobset.scan(substr).to_a
|
58
|
+
@current_page = 1
|
59
|
+
@count = @total_size = resultset.size
|
60
|
+
resultset
|
61
|
+
end
|
62
|
+
|
63
|
+
def filtering(which)
|
64
|
+
erb(:filtering, locals: {which: which})
|
65
|
+
end
|
66
|
+
|
67
|
+
def filter_link(jid, within = "retries")
|
68
|
+
if within.nil?
|
69
|
+
::Rack::Utils.escape_html(jid)
|
70
|
+
else
|
71
|
+
"<a href='#{root_path}filter/#{within}?substr=#{jid}'>#{::Rack::Utils.escape_html(jid)}</a>"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def display_tags(job, within = "retries")
|
76
|
+
job.tags.map { |tag|
|
77
|
+
"<span class='label label-info jobtag'>#{filter_link(tag, within)}</span>"
|
78
|
+
}.join(" ")
|
54
79
|
end
|
55
80
|
|
56
81
|
# This view helper provide ability display you html code in
|
@@ -111,13 +136,6 @@ module Sidekiq
|
|
111
136
|
end
|
112
137
|
end
|
113
138
|
|
114
|
-
# within is used by Sidekiq Pro
|
115
|
-
def display_tags(job, within = nil)
|
116
|
-
job.tags.map { |tag|
|
117
|
-
"<span class='label label-info jobtag'>#{::Rack::Utils.escape_html(tag)}</span>"
|
118
|
-
}.join(" ")
|
119
|
-
end
|
120
|
-
|
121
139
|
# sidekiq/sidekiq#3243
|
122
140
|
def unfiltered?
|
123
141
|
yield unless env["PATH_INFO"].start_with?("/filter/")
|
@@ -278,23 +296,13 @@ module Sidekiq
|
|
278
296
|
elsif rss_kb < 10_000_000
|
279
297
|
"#{number_with_delimiter((rss_kb / 1024.0).to_i)} MB"
|
280
298
|
else
|
281
|
-
"#{number_with_delimiter((rss_kb / (1024.0 * 1024.0))
|
299
|
+
"#{number_with_delimiter((rss_kb / (1024.0 * 1024.0)), precision: 1)} GB"
|
282
300
|
end
|
283
301
|
end
|
284
302
|
|
285
|
-
def number_with_delimiter(number)
|
286
|
-
|
287
|
-
|
288
|
-
begin
|
289
|
-
Float(number)
|
290
|
-
rescue ArgumentError, TypeError
|
291
|
-
return number
|
292
|
-
end
|
293
|
-
|
294
|
-
options = {delimiter: ",", separator: "."}
|
295
|
-
parts = number.to_s.to_str.split(".")
|
296
|
-
parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
|
297
|
-
parts.join(options[:separator])
|
303
|
+
def number_with_delimiter(number, options = {})
|
304
|
+
precision = options[:precision] || 0
|
305
|
+
%(<span data-nwp="#{precision}">#{number.round(precision)}</span>)
|
298
306
|
end
|
299
307
|
|
300
308
|
def h(text)
|
data/lib/sidekiq/web.rb
CHANGED
@@ -34,6 +34,18 @@ module Sidekiq
|
|
34
34
|
"Metrics" => "metrics"
|
35
35
|
}
|
36
36
|
|
37
|
+
if Gem::Version.new(Rack::RELEASE) < Gem::Version.new("3")
|
38
|
+
CONTENT_LANGUAGE = "Content-Language"
|
39
|
+
CONTENT_SECURITY_POLICY = "Content-Security-Policy"
|
40
|
+
LOCATION = "Location"
|
41
|
+
X_CASCADE = "X-Cascade"
|
42
|
+
else
|
43
|
+
CONTENT_LANGUAGE = "content-language"
|
44
|
+
CONTENT_SECURITY_POLICY = "content-security-policy"
|
45
|
+
LOCATION = "location"
|
46
|
+
X_CASCADE = "x-cascade"
|
47
|
+
end
|
48
|
+
|
37
49
|
class << self
|
38
50
|
def settings
|
39
51
|
self
|
@@ -137,7 +149,7 @@ module Sidekiq
|
|
137
149
|
m = middlewares
|
138
150
|
|
139
151
|
rules = []
|
140
|
-
rules = [[:all, {
|
152
|
+
rules = [[:all, {Rack::CACHE_CONTROL => "private, max-age=86400"}]] unless ENV["SIDEKIQ_WEB_TESTING"]
|
141
153
|
|
142
154
|
::Rack::Builder.new do
|
143
155
|
use Rack::Static, urls: ["/stylesheets", "/images", "/javascripts"],
|
@@ -33,6 +33,7 @@ function addListeners() {
|
|
33
33
|
|
34
34
|
addShiftClickListeners()
|
35
35
|
updateFuzzyTimes();
|
36
|
+
updateNumbers();
|
36
37
|
setLivePollFromUrl();
|
37
38
|
|
38
39
|
var buttons = document.querySelectorAll(".live-poll");
|
@@ -102,6 +103,20 @@ function updateFuzzyTimes() {
|
|
102
103
|
t.cancel();
|
103
104
|
}
|
104
105
|
|
106
|
+
function updateNumbers() {
|
107
|
+
document.querySelectorAll("[data-nwp]").forEach(node => {
|
108
|
+
let number = parseFloat(node.textContent);
|
109
|
+
let precision = parseInt(node.dataset["nwp"] || 0);
|
110
|
+
if (typeof number === "number") {
|
111
|
+
let formatted = number.toLocaleString(undefined, {
|
112
|
+
minimumFractionDigits: precision,
|
113
|
+
maximumFractionDigits: precision,
|
114
|
+
});
|
115
|
+
node.textContent = formatted;
|
116
|
+
}
|
117
|
+
});
|
118
|
+
}
|
119
|
+
|
105
120
|
function setLivePollFromUrl() {
|
106
121
|
var url_params = new URL(window.location.href).searchParams
|
107
122
|
|
@@ -140,6 +155,7 @@ function checkResponse(resp) {
|
|
140
155
|
|
141
156
|
function scheduleLivePoll() {
|
142
157
|
let ti = parseInt(localStorage.sidekiqTimeInterval) || 5000;
|
158
|
+
if (ti < 2000) { ti = 2000 }
|
143
159
|
livePollTimer = setTimeout(livePollCallback, ti);
|
144
160
|
}
|
145
161
|
|
@@ -57,7 +57,9 @@ class DashboardChart extends BaseChart {
|
|
57
57
|
class RealtimeChart extends DashboardChart {
|
58
58
|
constructor(el, options) {
|
59
59
|
super(el, options);
|
60
|
-
|
60
|
+
let d = parseInt(localStorage.sidekiqTimeInterval) || 5000;
|
61
|
+
if (d < 2000) { d = 2000; }
|
62
|
+
this.delay = d
|
61
63
|
this.startPolling();
|
62
64
|
document.addEventListener("interval:update", this.handleUpdate.bind(this));
|
63
65
|
}
|
@@ -84,6 +86,7 @@ class RealtimeChart extends DashboardChart {
|
|
84
86
|
updateStatsSummary(this.stats.sidekiq);
|
85
87
|
updateRedisStats(this.stats.redis);
|
86
88
|
updateFooterUTCTime(this.stats.server_utc_time);
|
89
|
+
updateNumbers();
|
87
90
|
pulseBeacon();
|
88
91
|
|
89
92
|
this.stats = stats;
|
@@ -164,3 +167,16 @@ class RealtimeChart extends DashboardChart {
|
|
164
167
|
};
|
165
168
|
}
|
166
169
|
}
|
170
|
+
|
171
|
+
var rc = document.getElementById("realtime-chart")
|
172
|
+
if (rc != null) {
|
173
|
+
var rtc = new RealtimeChart(rc, JSON.parse(rc.textContent))
|
174
|
+
rtc.registerLegend(document.getElementById("realtime-legend"))
|
175
|
+
window.realtimeChart = rtc
|
176
|
+
}
|
177
|
+
|
178
|
+
var hc = document.getElementById("history-chart")
|
179
|
+
if (hc != null) {
|
180
|
+
var htc = new DashboardChart(hc, JSON.parse(hc.textContent))
|
181
|
+
window.historyChart = htc
|
182
|
+
}
|
@@ -1,15 +1,13 @@
|
|
1
1
|
Sidekiq = {};
|
2
2
|
|
3
|
-
var nf = new Intl.NumberFormat();
|
4
|
-
|
5
3
|
var updateStatsSummary = function(data) {
|
6
|
-
document.getElementById("txtProcessed").innerText =
|
7
|
-
document.getElementById("txtFailed").innerText =
|
8
|
-
document.getElementById("txtBusy").innerText =
|
9
|
-
document.getElementById("txtScheduled").innerText =
|
10
|
-
document.getElementById("txtRetries").innerText =
|
11
|
-
document.getElementById("txtEnqueued").innerText =
|
12
|
-
document.getElementById("txtDead").innerText =
|
4
|
+
document.getElementById("txtProcessed").innerText = data.processed;
|
5
|
+
document.getElementById("txtFailed").innerText = data.failed;
|
6
|
+
document.getElementById("txtBusy").innerText = data.busy;
|
7
|
+
document.getElementById("txtScheduled").innerText = data.scheduled;
|
8
|
+
document.getElementById("txtRetries").innerText = data.retries;
|
9
|
+
document.getElementById("txtEnqueued").innerText = data.enqueued;
|
10
|
+
document.getElementById("txtDead").innerText = data.dead;
|
13
11
|
}
|
14
12
|
|
15
13
|
var updateRedisStats = function(data) {
|
@@ -262,3 +262,37 @@ class HistBubbleChart extends BaseChart {
|
|
262
262
|
};
|
263
263
|
}
|
264
264
|
}
|
265
|
+
|
266
|
+
var ch = document.getElementById("job-metrics-overview-chart");
|
267
|
+
if (ch != null) {
|
268
|
+
var jm = new JobMetricsOverviewChart(ch, JSON.parse(ch.textContent));
|
269
|
+
document.querySelectorAll(".metrics-swatch-wrapper > input[type=checkbox]").forEach((imp) => {
|
270
|
+
jm.registerSwatch(imp.id)
|
271
|
+
});
|
272
|
+
window.jobMetricsChart = jm;
|
273
|
+
}
|
274
|
+
|
275
|
+
var htc = document.getElementById("hist-totals-chart");
|
276
|
+
if (htc != null) {
|
277
|
+
var tc = new HistTotalsChart(htc, JSON.parse(htc.textContent));
|
278
|
+
window.histTotalsChart = tc
|
279
|
+
}
|
280
|
+
|
281
|
+
var hbc = document.getElementById("hist-bubble-chart");
|
282
|
+
if (hbc != null) {
|
283
|
+
var bc = new HistBubbleChart(hbc, JSON.parse(hbc.textContent));
|
284
|
+
window.histBubbleChart = bc
|
285
|
+
}
|
286
|
+
|
287
|
+
var form = document.getElementById("metrics-form")
|
288
|
+
document.querySelectorAll("#period-selector").forEach(node => {
|
289
|
+
node.addEventListener("input", debounce(() => form.submit()))
|
290
|
+
})
|
291
|
+
|
292
|
+
function debounce(func, timeout = 300) {
|
293
|
+
let timer;
|
294
|
+
return (...args) => {
|
295
|
+
clearTimeout(timer);
|
296
|
+
timer = setTimeout(() => { func.apply(this, args); }, timeout);
|
297
|
+
};
|
298
|
+
}
|
data/web/locales/en.yml
CHANGED
data/web/locales/pt-br.yml
CHANGED
@@ -5,10 +5,13 @@
|
|
5
5
|
AreYouSureDeleteJob: Deseja deletar esta tarefa?
|
6
6
|
AreYouSureDeleteQueue: Deseja deletar a fila %{queue}? Isso irá deletar todas as tarefas desta fila.
|
7
7
|
Arguments: Argumentos
|
8
|
+
AvgExecutionTime: Tempo médio de execução
|
8
9
|
BackToApp: De volta ao aplicativo
|
10
|
+
Bucket: Bucket
|
9
11
|
Busy: Ocupados
|
10
12
|
Class: Classe
|
11
13
|
Connections: Conexões
|
14
|
+
Context: Contexto
|
12
15
|
CreatedAt: Criado em
|
13
16
|
CurrentMessagesInQueue: Mensagens atualmente na <span class='title'>%{queue}</span>
|
14
17
|
Dashboard: Painel
|
@@ -16,13 +19,16 @@
|
|
16
19
|
DeadJobs: Tarefas mortas
|
17
20
|
Delete: Apagar
|
18
21
|
DeleteAll: Apagar tudo
|
22
|
+
Deploy: Deploy
|
19
23
|
Enqueued: Na fila
|
20
24
|
Error: Erro
|
21
25
|
ErrorBacktrace: Rastreamento do erro
|
22
26
|
ErrorClass: Classe de erro
|
23
27
|
ErrorMessage: Mensagem de erro
|
28
|
+
ExecutionTime: Tempo de execução
|
24
29
|
Extras: Extras
|
25
30
|
Failed: Falhas
|
31
|
+
Failure: Falha
|
26
32
|
Failures: Falhas
|
27
33
|
GoBack: ← Voltar
|
28
34
|
History: Histórico
|
@@ -34,10 +40,13 @@
|
|
34
40
|
Latency: Latência
|
35
41
|
LivePoll: Live Poll
|
36
42
|
MemoryUsage: Uso de memória
|
43
|
+
Metrics: Métricas
|
37
44
|
Name: Nome
|
38
45
|
Namespace: Namespace
|
39
46
|
NextRetry: Próxima Tentativa
|
47
|
+
NoDataFound: Nenhum dado encontrado
|
40
48
|
NoDeadJobsFound: Nenhuma tarefa morta foi encontrada
|
49
|
+
NoJobMetricsFound: Nenhuma métrica de tarefa encontrada
|
41
50
|
NoRetriesFound: Nenhuma tentativa encontrada
|
42
51
|
NoScheduledFound: Nenhuma tarefa agendada foi encontrada
|
43
52
|
NotYetEnqueued: Ainda não enfileirado
|
@@ -47,6 +56,7 @@
|
|
47
56
|
Pause: Pausar
|
48
57
|
Paused: Pausado
|
49
58
|
PeakMemoryUsage: Pico de uso de memória
|
59
|
+
Uptime: Tempo de atividade
|
50
60
|
Plugins: Plug-ins
|
51
61
|
PollingInterval: Intervalo de Polling
|
52
62
|
Process: Processo
|
@@ -63,14 +73,24 @@
|
|
63
73
|
RetryNow: Tentar novamente agora
|
64
74
|
Scheduled: Agendados
|
65
75
|
ScheduledJobs: Tarefas agendadas
|
76
|
+
idle: Ocioso
|
77
|
+
active: Ativo
|
78
|
+
Seconds: Segundos
|
66
79
|
ShowAll: Mostrar todos
|
67
80
|
SixMonths: 6 meses
|
68
81
|
Size: Tamanho
|
82
|
+
Started: Iniciado
|
69
83
|
Stop: Parar
|
70
84
|
StopAll: Parar Todos
|
71
85
|
StopPolling: Parar Polling
|
86
|
+
Success: Sucesso
|
87
|
+
Summary: Resumo
|
72
88
|
Thread: Thread
|
73
89
|
Threads: Threads
|
90
|
+
ThreeMonths: 3 meses
|
91
|
+
TotalExecutionTime: Tempo total de execução
|
74
92
|
Unpause: Despausar
|
75
93
|
Utilization: Utilização
|
94
|
+
Version: Versão
|
95
|
+
When: Quando
|
76
96
|
Worker: Trabalhador
|
data/web/views/_job_info.erb
CHANGED
data/web/views/_summary.erb
CHANGED
@@ -1,39 +1,39 @@
|
|
1
1
|
<ul class="list-unstyled summary row">
|
2
2
|
<li class="processed col-sm-1">
|
3
|
-
<span id="txtProcessed" class="count"><%=
|
3
|
+
<span id="txtProcessed" class="count" data-nwp><%= stats.processed %></span>
|
4
4
|
<span class="desc"><%= t('Processed') %></span>
|
5
5
|
</li>
|
6
6
|
<li class="failed col-sm-1">
|
7
|
-
<span id="txtFailed" class="count"><%=
|
7
|
+
<span id="txtFailed" class="count" data-nwp><%= stats.failed %></span>
|
8
8
|
<span class="desc"><%= t('Failed') %></span>
|
9
9
|
</li>
|
10
10
|
<li class="busy col-sm-1">
|
11
11
|
<a href="<%= root_path %>busy">
|
12
|
-
<span id="txtBusy" class="count"><%=
|
12
|
+
<span id="txtBusy" class="count" data-nwp><%= workset.size %></span>
|
13
13
|
<span class="desc"><%= t('Busy') %></span>
|
14
14
|
</a>
|
15
15
|
</li>
|
16
16
|
<li class="enqueued col-sm-1">
|
17
17
|
<a href="<%= root_path %>queues">
|
18
|
-
<span id="txtEnqueued" class="count"><%=
|
18
|
+
<span id="txtEnqueued" class="count" data-nwp><%= stats.enqueued %></span>
|
19
19
|
<span class="desc"><%= t('Enqueued') %></span>
|
20
20
|
</a>
|
21
21
|
</li>
|
22
22
|
<li class="retries col-sm-1">
|
23
23
|
<a href="<%= root_path %>retries">
|
24
|
-
<span id="txtRetries" class="count"><%=
|
24
|
+
<span id="txtRetries" class="count" data-nwp><%= stats.retry_size %></span>
|
25
25
|
<span class="desc"><%= t('Retries') %></span>
|
26
26
|
</a>
|
27
27
|
</li>
|
28
28
|
<li class="scheduled col-sm-1">
|
29
29
|
<a href="<%= root_path %>scheduled">
|
30
|
-
<span id="txtScheduled" class="count"><%=
|
30
|
+
<span id="txtScheduled" class="count" data-nwp><%= stats.scheduled_size %></span>
|
31
31
|
<span class="desc"><%= t('Scheduled') %></span>
|
32
32
|
</a>
|
33
33
|
</li>
|
34
34
|
<li class="dead col-sm-1">
|
35
35
|
<a href="<%= root_path %>morgue">
|
36
|
-
<span id="txtDead" class="count"><%=
|
36
|
+
<span id="txtDead" class="count" data-nwp><%= stats.dead_size %></span>
|
37
37
|
<span class="desc"><%= t('Dead') %></span>
|
38
38
|
</a>
|
39
39
|
</li>
|
data/web/views/busy.erb
CHANGED
@@ -86,9 +86,9 @@
|
|
86
86
|
<% end %>
|
87
87
|
</td>
|
88
88
|
<td><%= relative_time(Time.at(process['started_at'])) %></td>
|
89
|
-
<td><%= format_memory(process['rss'].to_i) %></td>
|
90
|
-
<td><%= process['concurrency'] %></td>
|
91
|
-
<td><%= process['busy'] %></td>
|
89
|
+
<td class="num"><%= format_memory(process['rss'].to_i) %></td>
|
90
|
+
<td class="num"><%= number_with_delimiter(process['concurrency']) %></td>
|
91
|
+
<td class="num"><%= number_with_delimiter(process['busy']) %></td>
|
92
92
|
<td>
|
93
93
|
<% unless process.embedded? %>
|
94
94
|
<form method="POST">
|
data/web/views/dashboard.erb
CHANGED
@@ -1,7 +1,3 @@
|
|
1
|
-
<script type="text/javascript" src="<%= root_path %>javascripts/chart.min.js"></script>
|
2
|
-
<script type="text/javascript" src="<%= root_path %>javascripts/chartjs-plugin-annotation.min.js"></script>
|
3
|
-
<script type="text/javascript" src="<%= root_path %>javascripts/base-charts.js"></script>
|
4
|
-
<script type="text/javascript" src="<%= root_path %>javascripts/dashboard-charts.js"></script>
|
5
1
|
<script type="text/javascript" src="<%= root_path %>javascripts/dashboard.js"></script>
|
6
2
|
<div class= "dashboard clearfix">
|
7
3
|
<h3 >
|
@@ -20,26 +16,19 @@
|
|
20
16
|
</div>
|
21
17
|
|
22
18
|
<div class="row chart">
|
23
|
-
<canvas id="realtime-chart"
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
updateUrl: "#{root_path}stats",
|
34
|
-
}) %>
|
35
|
-
)
|
36
|
-
</script>
|
19
|
+
<canvas id="realtime-chart">
|
20
|
+
<%= to_json({
|
21
|
+
processedLabel: t('Processed'),
|
22
|
+
failedLabel: t('Failed'),
|
23
|
+
labels: Array.new(50, ""),
|
24
|
+
processed: Array.new(50),
|
25
|
+
failed: Array.new(50),
|
26
|
+
updateUrl: "#{root_path}stats",
|
27
|
+
}) %>
|
28
|
+
</canvas>
|
37
29
|
|
38
30
|
<!-- start with a space in the legend so the height doesn't change when we add content dynamically -->
|
39
31
|
<div id="realtime-legend"> </div>
|
40
|
-
<script>
|
41
|
-
realtimeChart.registerLegend(document.getElementById("realtime-legend"))
|
42
|
-
</script>
|
43
32
|
</div>
|
44
33
|
|
45
34
|
<div class="row header">
|
@@ -55,18 +44,14 @@
|
|
55
44
|
<a href="<%= root_path %>?days=180" class="history-graph <%= "active" if params[:days] == "180" %>"><%= t('SixMonths') %></a>
|
56
45
|
</div>
|
57
46
|
|
58
|
-
<canvas id="history-chart"
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
failed: @failed_history.to_a.reverse,
|
67
|
-
}) %>
|
68
|
-
)
|
69
|
-
</script>
|
47
|
+
<canvas id="history-chart">
|
48
|
+
<%= to_json({
|
49
|
+
processedLabel: t('Processed'),
|
50
|
+
failedLabel: t('Failed'),
|
51
|
+
processed: @processed_history.to_a.reverse,
|
52
|
+
failed: @failed_history.to_a.reverse,
|
53
|
+
}) %>
|
54
|
+
</canvas>
|
70
55
|
</div>
|
71
56
|
|
72
57
|
<br/>
|
@@ -113,3 +98,8 @@
|
|
113
98
|
<% end %>
|
114
99
|
</div>
|
115
100
|
</div>
|
101
|
+
|
102
|
+
<script type="text/javascript" src="<%= root_path %>javascripts/chart.min.js"></script>
|
103
|
+
<script type="text/javascript" src="<%= root_path %>javascripts/chartjs-plugin-annotation.min.js"></script>
|
104
|
+
<script type="text/javascript" src="<%= root_path %>javascripts/base-charts.js"></script>
|
105
|
+
<script type="text/javascript" src="<%= root_path %>javascripts/dashboard-charts.js"></script>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<div>
|
2
|
+
<form method="post" class="form-inline" action='<%= root_path %>filter/<%= which %>'>
|
3
|
+
<%= csrf_tag %>
|
4
|
+
<label for="substr"><%= t('Filter') %></label>
|
5
|
+
<input class="search form-control" type="search" name="substr" value="<%= h params[:substr] %>" placeholder="<%= t('AnyJobContent') %>"/>
|
6
|
+
</form>
|
7
|
+
</div>
|