sidekiq 5.2.10 → 6.5.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +422 -1
  3. data/LICENSE +3 -3
  4. data/README.md +24 -35
  5. data/bin/sidekiq +27 -3
  6. data/bin/sidekiqload +79 -67
  7. data/bin/sidekiqmon +8 -0
  8. data/lib/generators/sidekiq/job_generator.rb +57 -0
  9. data/lib/generators/sidekiq/templates/{worker.rb.erb → job.rb.erb} +2 -2
  10. data/lib/generators/sidekiq/templates/{worker_spec.rb.erb → job_spec.rb.erb} +1 -1
  11. data/lib/generators/sidekiq/templates/{worker_test.rb.erb → job_test.rb.erb} +1 -1
  12. data/lib/sidekiq/api.rb +527 -310
  13. data/lib/sidekiq/cli.rb +204 -208
  14. data/lib/sidekiq/client.rb +78 -82
  15. data/lib/sidekiq/component.rb +65 -0
  16. data/lib/sidekiq/delay.rb +8 -7
  17. data/lib/sidekiq/extensions/action_mailer.rb +13 -22
  18. data/lib/sidekiq/extensions/active_record.rb +13 -10
  19. data/lib/sidekiq/extensions/class_methods.rb +14 -11
  20. data/lib/sidekiq/extensions/generic_proxy.rb +7 -5
  21. data/lib/sidekiq/fetch.rb +50 -40
  22. data/lib/sidekiq/job.rb +13 -0
  23. data/lib/sidekiq/job_logger.rb +33 -7
  24. data/lib/sidekiq/job_retry.rb +126 -106
  25. data/lib/sidekiq/job_util.rb +71 -0
  26. data/lib/sidekiq/launcher.rb +177 -83
  27. data/lib/sidekiq/logger.rb +156 -0
  28. data/lib/sidekiq/manager.rb +40 -41
  29. data/lib/sidekiq/metrics/deploy.rb +47 -0
  30. data/lib/sidekiq/metrics/query.rb +153 -0
  31. data/lib/sidekiq/metrics/shared.rb +94 -0
  32. data/lib/sidekiq/metrics/tracking.rb +134 -0
  33. data/lib/sidekiq/middleware/chain.rb +102 -46
  34. data/lib/sidekiq/middleware/current_attributes.rb +63 -0
  35. data/lib/sidekiq/middleware/i18n.rb +7 -7
  36. data/lib/sidekiq/middleware/modules.rb +21 -0
  37. data/lib/sidekiq/monitor.rb +133 -0
  38. data/lib/sidekiq/paginator.rb +28 -16
  39. data/lib/sidekiq/processor.rb +104 -97
  40. data/lib/sidekiq/rails.rb +46 -37
  41. data/lib/sidekiq/redis_client_adapter.rb +154 -0
  42. data/lib/sidekiq/redis_connection.rb +108 -77
  43. data/lib/sidekiq/ring_buffer.rb +29 -0
  44. data/lib/sidekiq/scheduled.rb +105 -42
  45. data/lib/sidekiq/sd_notify.rb +149 -0
  46. data/lib/sidekiq/systemd.rb +24 -0
  47. data/lib/sidekiq/testing/inline.rb +6 -5
  48. data/lib/sidekiq/testing.rb +68 -58
  49. data/lib/sidekiq/transaction_aware_client.rb +45 -0
  50. data/lib/sidekiq/version.rb +2 -1
  51. data/lib/sidekiq/web/action.rb +15 -11
  52. data/lib/sidekiq/web/application.rb +103 -77
  53. data/lib/sidekiq/web/csrf_protection.rb +180 -0
  54. data/lib/sidekiq/web/helpers.rb +125 -95
  55. data/lib/sidekiq/web/router.rb +23 -19
  56. data/lib/sidekiq/web.rb +65 -105
  57. data/lib/sidekiq/worker.rb +259 -109
  58. data/lib/sidekiq.rb +170 -62
  59. data/sidekiq.gemspec +23 -16
  60. data/web/assets/images/apple-touch-icon.png +0 -0
  61. data/web/assets/javascripts/application.js +113 -61
  62. data/web/assets/javascripts/chart.min.js +13 -0
  63. data/web/assets/javascripts/chartjs-plugin-annotation.min.js +7 -0
  64. data/web/assets/javascripts/dashboard.js +53 -89
  65. data/web/assets/javascripts/graph.js +16 -0
  66. data/web/assets/javascripts/metrics.js +262 -0
  67. data/web/assets/stylesheets/application-dark.css +143 -0
  68. data/web/assets/stylesheets/application-rtl.css +0 -4
  69. data/web/assets/stylesheets/application.css +88 -233
  70. data/web/locales/ar.yml +8 -2
  71. data/web/locales/de.yml +14 -2
  72. data/web/locales/el.yml +43 -19
  73. data/web/locales/en.yml +13 -1
  74. data/web/locales/es.yml +18 -2
  75. data/web/locales/fr.yml +10 -3
  76. data/web/locales/ja.yml +14 -1
  77. data/web/locales/lt.yml +83 -0
  78. data/web/locales/pl.yml +4 -4
  79. data/web/locales/pt-br.yml +27 -9
  80. data/web/locales/ru.yml +4 -0
  81. data/web/locales/vi.yml +83 -0
  82. data/web/locales/zh-cn.yml +36 -11
  83. data/web/locales/zh-tw.yml +32 -7
  84. data/web/views/_footer.erb +1 -1
  85. data/web/views/_job_info.erb +3 -2
  86. data/web/views/_nav.erb +1 -1
  87. data/web/views/_poll_link.erb +2 -5
  88. data/web/views/_summary.erb +7 -7
  89. data/web/views/busy.erb +61 -22
  90. data/web/views/dashboard.erb +23 -14
  91. data/web/views/dead.erb +3 -3
  92. data/web/views/layout.erb +3 -1
  93. data/web/views/metrics.erb +69 -0
  94. data/web/views/metrics_for_job.erb +87 -0
  95. data/web/views/morgue.erb +9 -6
  96. data/web/views/queue.erb +23 -10
  97. data/web/views/queues.erb +10 -2
  98. data/web/views/retries.erb +11 -8
  99. data/web/views/retry.erb +3 -3
  100. data/web/views/scheduled.erb +5 -2
  101. metadata +58 -63
  102. data/.circleci/config.yml +0 -61
  103. data/.github/contributing.md +0 -32
  104. data/.github/issue_template.md +0 -11
  105. data/.gitignore +0 -15
  106. data/.travis.yml +0 -11
  107. data/3.0-Upgrade.md +0 -70
  108. data/4.0-Upgrade.md +0 -53
  109. data/5.0-Upgrade.md +0 -56
  110. data/COMM-LICENSE +0 -97
  111. data/Ent-Changes.md +0 -238
  112. data/Gemfile +0 -19
  113. data/Pro-2.0-Upgrade.md +0 -138
  114. data/Pro-3.0-Upgrade.md +0 -44
  115. data/Pro-4.0-Upgrade.md +0 -35
  116. data/Pro-Changes.md +0 -759
  117. data/Rakefile +0 -9
  118. data/bin/sidekiqctl +0 -20
  119. data/code_of_conduct.md +0 -50
  120. data/lib/generators/sidekiq/worker_generator.rb +0 -49
  121. data/lib/sidekiq/core_ext.rb +0 -1
  122. data/lib/sidekiq/ctl.rb +0 -221
  123. data/lib/sidekiq/exception_handler.rb +0 -29
  124. data/lib/sidekiq/logging.rb +0 -122
  125. data/lib/sidekiq/middleware/server/active_record.rb +0 -23
  126. data/lib/sidekiq/util.rb +0 -66
@@ -7,6 +7,7 @@ zh-tw: # <---- change this to your locale code
7
7
  Realtime: 即時
8
8
  History: 歷史資料
9
9
  Busy: 忙碌
10
+ Utilization: 使用率
10
11
  Processed: 已處理
11
12
  Failed: 已失敗
12
13
  Scheduled: 已排程
@@ -25,26 +26,28 @@ zh-tw: # <---- change this to your locale code
25
26
  CurrentMessagesInQueue: 目前在<span class='title'>%{queue}</span>的工作
26
27
  Delete: 刪除
27
28
  AddToQueue: 增加至佇列
28
- AreYouSureDeleteJob: 你確定要刪除這個工作嗎?
29
- AreYouSureDeleteQueue: 你確定要刪除%{queue}這個佇列?
29
+ AreYouSureDeleteJob: 確定要刪除這個工作嗎?
30
+ AreYouSureDeleteQueue: 確定要刪除%{queue}佇列?這會刪除佇列裡的所有工作,佇列將會在有新工作時重新出現。
30
31
  Queues: 佇列
31
32
  Size: 容量
32
33
  Actions: 動作
33
34
  NextRetry: 下次重試
34
35
  RetryCount: 重試次數
35
36
  RetryNow: 馬上重試
37
+ Kill: 取消
36
38
  LastRetry: 最後一次重試
37
39
  OriginallyFailed: 原本已失敗
38
40
  AreYouSure: 你確定?
39
- DeleteAll: 刪除全部
40
- RetryAll: 重試全部
41
- NoRetriesFound: 沒有發現可重試
41
+ DeleteAll: 全部刪除
42
+ RetryAll: 全部重試
43
+ KillAll: 全部取消
44
+ NoRetriesFound: 找無可重試的工作
42
45
  Error: 錯誤
43
46
  ErrorClass: 錯誤類別
44
47
  ErrorMessage: 錯誤訊息
45
- ErrorBacktrace: 錯誤的回調追踨
48
+ ErrorBacktrace: 詳細錯誤訊息
46
49
  GoBack: ← 返回
47
- NoScheduledFound: 沒有發現已排程的工作
50
+ NoScheduledFound: 找無已排程的工作
48
51
  When: 當
49
52
  ScheduledJobs: 已排程的工作
50
53
  idle: 閒置
@@ -62,7 +65,29 @@ zh-tw: # <---- change this to your locale code
62
65
  DeadJobs: 停滯工作
63
66
  NoDeadJobsFound: 沒有發現任何停滯的工作
64
67
  Dead: 停滯
68
+ Process: 程序
65
69
  Processes: 處理中
70
+ Name: 名稱
66
71
  Thread: 執行緒
67
72
  Threads: 執行緒
68
73
  Jobs: 工作
74
+ Paused: 已暫停
75
+ Stop: 強制暫停
76
+ Quiet: 暫停
77
+ StopAll: 全部強制暫停
78
+ QuietAll: 全部暫停
79
+ PollingInterval: 輪詢週期
80
+ Plugins: 套件
81
+ NotYetEnqueued: 尚未進入佇列
82
+ CreatedAt: 建立時間
83
+ BackToApp: 回首頁
84
+ Latency: 延時
85
+ Pause: 暫停
86
+ Unpause: 取消暫停
87
+ Metrics: 計量
88
+ NoDataFound: 找無資料
89
+ TotalExecutionTime: 總執行時間
90
+ AvgExecutionTime: 平均執行時間
91
+ Context: 上下文
92
+ Bucket: 桶
93
+ NoJobMetricsFound: 找無工作相關計量資料
@@ -9,7 +9,7 @@
9
9
  <p class="navbar-text redis-url" title="<%= redis_connection_and_namespace %>"><%= redis_connection_and_namespace %></p>
10
10
  </li>
11
11
  <li>
12
- <p class="navbar-text server-utc-time"><%= server_utc_time %></p>
12
+ <p id="serverUtcTime" class="navbar-text server-utc-time"><%= server_utc_time %></p>
13
13
  </li>
14
14
  <li>
15
15
  <p class="navbar-text"><a style="color: gray;" href="https://github.com/mperham/sidekiq/wiki">docs</a></p>
@@ -3,7 +3,7 @@
3
3
  </header>
4
4
 
5
5
  <div class="table_container">
6
- <table class="table table-bordered table-striped">
6
+ <table class="table table-bordered table-striped table-hover">
7
7
  <tbody>
8
8
  <tr>
9
9
  <th><%= t('Queue') %></th>
@@ -14,7 +14,8 @@
14
14
  <tr>
15
15
  <th><%= t('Job') %></th>
16
16
  <td>
17
- <code><%= job.display_class %></code>
17
+ <%= job.display_class %>
18
+ <%= display_tags(job) %>
18
19
  </td>
19
20
  </tr>
20
21
  <tr>
data/web/views/_nav.erb CHANGED
@@ -1,7 +1,7 @@
1
1
  <div class="navbar navbar-default navbar-fixed-top">
2
2
  <div class="container-fluid">
3
3
  <div class="navbar-header" data-navbar="static">
4
- <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-menu">
4
+ <button type="button" class="navbar-toggle collapsed" data-toggle="navbar-menu" data-target="#navbar-menu">
5
5
  <span class="icon-bar"></span>
6
6
  <span class="icon-bar"></span>
7
7
  <span class="icon-bar"></span>
@@ -1,7 +1,4 @@
1
1
  <% if current_path != '' %>
2
- <% if params[:poll] %>
3
- <a id="live-poll" class="btn btn-primary active" href="<%= root_path + current_path %>"><%= t('StopPolling') %></a>
4
- <% else %>
5
- <a id="live-poll" class="btn btn-primary" href="<%= root_path + current_path %>?<%= qparams(poll: true) %>"><%= t('LivePoll') %></a>
6
- <% end %>
2
+ <a class="live-poll-start live-poll btn btn-primary"><%= t('LivePoll') %></a>
3
+ <a class="live-poll-stop live-poll btn btn-primary active"><%= t('StopPolling') %></a>
7
4
  <% end %>
@@ -1,39 +1,39 @@
1
1
  <ul class="list-unstyled summary row">
2
2
  <li class="processed col-sm-1">
3
- <span class="count"><%= number_with_delimiter(stats.processed) %></span>
3
+ <span id="txtProcessed" class="count"><%= number_with_delimiter(stats.processed) %></span>
4
4
  <span class="desc"><%= t('Processed') %></span>
5
5
  </li>
6
6
  <li class="failed col-sm-1">
7
- <span class="count"><%= number_with_delimiter(stats.failed) %></span>
7
+ <span id="txtFailed" class="count"><%= number_with_delimiter(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 class="count"><%= number_with_delimiter(workers.size) %></span>
12
+ <span id="txtBusy" class="count"><%= number_with_delimiter(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 class="count"><%= number_with_delimiter(stats.enqueued) %></span>
18
+ <span id="txtEnqueued" class="count"><%= number_with_delimiter(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 class="count"><%= number_with_delimiter(stats.retry_size) %></span>
24
+ <span id="txtRetries" class="count"><%= number_with_delimiter(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 class="count"><%= number_with_delimiter(stats.scheduled_size) %></span>
30
+ <span id="txtScheduled" class="count"><%= number_with_delimiter(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 class="count"><%= number_with_delimiter(stats.dead_size) %></span>
36
+ <span id="txtDead" class="count"><%= number_with_delimiter(stats.dead_size) %></span>
37
37
  <span class="desc"><%= t('Dead') %></span>
38
38
  </a>
39
39
  </li>
data/web/views/busy.erb CHANGED
@@ -1,8 +1,39 @@
1
1
  <div class="row header">
2
- <div class="col-sm-8 pull-left flip">
2
+ <div class="col-sm-4 pull-left flip">
3
+ <h3><%= t('Status') %></h3>
4
+ </div>
5
+ </div>
6
+
7
+ <div class="stats-wrapper">
8
+ <div class="stats-container">
9
+ <div class="stat">
10
+ <h3><%= s = processes.size; number_with_delimiter(s) %></h3>
11
+ <p><%= t('Processes') %></p>
12
+ </div>
13
+ <div class="stat">
14
+ <h3><%= x = processes.total_concurrency; number_with_delimiter(x) %></h3>
15
+ <p><%= t('Threads') %></p>
16
+ </div>
17
+ <div class="stat">
18
+ <h3><%= ws = workset.size; number_with_delimiter(ws) %></h3>
19
+ <p><%= t('Busy') %></p>
20
+ </div>
21
+ <div class="stat">
22
+ <h3><%= x == 0 ? 0 : ((ws / x.to_f) * 100).round(0) %>%</h3>
23
+ <p><%= t('Utilization') %></p>
24
+ </div>
25
+ <div class="stat">
26
+ <h3><%= format_memory(processes.total_rss) %></h3>
27
+ <p><%= t('RSS') %></p>
28
+ </div>
29
+ </div>
30
+ </div>
31
+
32
+ <div class="row header">
33
+ <div class="col-sm-4 pull-left flip">
3
34
  <h3><%= t('Processes') %></h3>
4
35
  </div>
5
- <div class="col-sm-4 pull-right flip">
36
+ <div class="col-sm-3 pull-right flip">
6
37
  <form method="POST" class="warning-messages">
7
38
  <%= csrf_tag %>
8
39
  <div class="btn-group pull-right flip">
@@ -12,18 +43,18 @@
12
43
  </form>
13
44
  </div>
14
45
  </div>
15
-
16
46
  <div class="table_container">
17
- <table class="processes table table-hover table-bordered table-striped table-white">
47
+ <table class="processes table table-hover table-bordered table-striped">
18
48
  <thead>
19
49
  <th><%= t('Name') %></th>
20
50
  <th><%= t('Started') %></th>
21
- <th><%= t('Threads') %></th>
22
- <th><%= t('Busy') %></th>
51
+ <th class="col-sm-1"><%= t('RSS') %><a target="blank" href="https://github.com/mperham/sidekiq/wiki/Memory#rss"><span class="info-circle" title="Click to learn more about RSS">?</span></a></th>
52
+ <th class="col-sm-1"><%= t('Threads') %></th>
53
+ <th class="col-sm-1"><%= t('Busy') %></th>
23
54
  <th>&nbsp;</th>
24
55
  </thead>
25
56
  <% lead = processes.leader %>
26
- <% processes.each do |process| %>
57
+ <% sorted_processes.each do |process| %>
27
58
  <tr>
28
59
  <td class="box">
29
60
  <%= "#{process['hostname']}:#{process['pid']}" %>
@@ -39,22 +70,22 @@
39
70
  <% end %>
40
71
  <br>
41
72
  <b><%= "#{t('Queues')}: " %></b>
42
- <%= process['queues'] * ", " %>
73
+ <%= process.queues.join(", ") %>
43
74
  </td>
44
75
  <td><%= relative_time(Time.at(process['started_at'])) %></td>
76
+ <td><%= format_memory(process['rss'].to_i) %></td>
45
77
  <td><%= process['concurrency'] %></td>
46
78
  <td><%= process['busy'] %></td>
47
79
  <td>
48
- <div class="btn-group pull-right flip">
49
- <form method="POST">
50
- <%= csrf_tag %>
51
- <input type="hidden" name="identity" value="<%= process['identity'] %>"/>
52
- <% unless process.stopping? %>
53
- <button class="btn btn-warn" type="submit" name="quiet" value="1"><%= t('Quiet') %></button>
54
- <% end %>
55
- <button class="btn btn-danger" type="submit" name="stop" value="1"><%= t('Stop') %></button>
56
- </form>
57
- </div>
80
+ <form method="POST">
81
+ <%= csrf_tag %>
82
+ <input type="hidden" name="identity" value="<%= process['identity'] %>"/>
83
+
84
+ <div class="btn-group pull-right flip">
85
+ <% unless process.stopping? %><button class="btn btn-xs btn-warn" type="submit" name="quiet" value="1"><%= t('Quiet') %></button><% end %>
86
+ <button class="btn btn-xs btn-danger" type="submit" name="stop" value="1"><%= t('Stop') %></button>
87
+ </div>
88
+ </form>
58
89
  </td>
59
90
  </tr>
60
91
  <% end %>
@@ -65,10 +96,15 @@
65
96
  <div class="col-sm-7">
66
97
  <h3><%= t('Jobs') %></h3>
67
98
  </div>
99
+ <% if @workset.size > 0 && @total_size > @count %>
100
+ <div class="col-sm-4">
101
+ <%= erb :_paging, locals: { url: "#{root_path}busy" } %>
102
+ </div>
103
+ <% end %>
68
104
  </div>
69
105
 
70
106
  <div class="table_container">
71
- <table class="workers table table-hover table-bordered table-striped table-white">
107
+ <table class="workers table table-hover table-bordered table-striped">
72
108
  <thead>
73
109
  <th><%= t('Process') %></th>
74
110
  <th><%= t('TID') %></th>
@@ -78,8 +114,8 @@
78
114
  <th><%= t('Arguments') %></th>
79
115
  <th><%= t('Started') %></th>
80
116
  </thead>
81
- <% workers.each do |process, thread, msg| %>
82
- <% job = Sidekiq::Job.new(msg['payload']) %>
117
+ <% @workset.each do |process, thread, msg| %>
118
+ <% job = Sidekiq::JobRecord.new(msg['payload']) %>
83
119
  <tr>
84
120
  <td><%= process %></td>
85
121
  <td><%= thread %></td>
@@ -87,7 +123,10 @@
87
123
  <td>
88
124
  <a href="<%= root_path %>queues/<%= msg['queue'] %>"><%= msg['queue'] %></a>
89
125
  </td>
90
- <td><%= job.display_class %></td>
126
+ <td>
127
+ <%= job.display_class %>
128
+ <%= display_tags(job, nil) %>
129
+ </td>
91
130
  <td>
92
131
  <div class="args"><%= display_args(job.display_args) %></div>
93
132
  </td>
@@ -1,17 +1,18 @@
1
+ <script type="text/javascript" src="<%= root_path %>javascripts/graph.js"></script>
1
2
  <script type="text/javascript" src="<%= root_path %>javascripts/dashboard.js"></script>
2
3
  <div class= "dashboard clearfix">
3
4
  <h3 >
4
5
  <%= t('Dashboard') %>
5
- <span class="beacon">
6
+ <span id="beacon" class="beacon">
6
7
  <span class="ring"></span>
7
8
  <span class="dot"></span>
8
9
  </span>
9
10
  </h3>
10
11
  <div class="interval-slider ltr">
11
12
  <span class="interval-slider-label"><%= t('PollingInterval') %>:</span>
12
- <span class="current-interval">5 sec</span>
13
+ <span id="sldr-text" class="current-interval">5 sec</span>
13
14
  <br/>
14
- <input type="range" min="2000" max="20000" step="1000" value="5000"/>
15
+ <input id="sldr" type="range" min="2000" max="20000" step="1000" value="5000"/>
15
16
  </div>
16
17
  </div>
17
18
 
@@ -20,54 +21,62 @@
20
21
  <div id="realtime-legend"></div>
21
22
  </div>
22
23
 
23
- <div class="row chart">
24
- <h5>
25
- <span class="history-heading"><%= t('History') %></span>
24
+ <div class="row header">
25
+ <div class="col-sm-4 pull-left flip">
26
+ <h3><%= t('History') %></h3>
27
+ </div>
28
+ </div>
29
+ <div class="row chart">
30
+ <div>
26
31
  <a href="<%= root_path %>?days=7" class="history-graph <%= "active" if params[:days] == "7" %>"><%= t('OneWeek') %></a>
27
32
  <a href="<%= root_path %>" class="history-graph <%= "active" if params[:days].nil? || params[:days] == "30" %>"><%= t('OneMonth') %></a>
28
33
  <a href="<%= root_path %>?days=90" class="history-graph <%= "active" if params[:days] == "90" %>"><%= t('ThreeMonths') %></a>
29
34
  <a href="<%= root_path %>?days=180" class="history-graph <%= "active" if params[:days] == "180" %>"><%= t('SixMonths') %></a>
30
- </h5>
35
+ </div>
31
36
 
32
37
  <div id="history" data-processed-label="<%= t('Processed') %>" data-failed-label="<%= t('Failed') %>" data-processed="<%= h Sidekiq.dump_json(@processed_history) %>" data-failed="<%= h Sidekiq.dump_json(@failed_history) %>" data-update-url="<%= root_path %>stats"></div>
33
38
  <div id="history-legend"></div>
34
39
  </div>
35
40
 
36
41
  <br/>
37
- <h5>Redis</h5>
38
- <div class="redis-wrapper">
42
+ <div class="row header">
43
+ <div class="col-sm-4 pull-left flip">
44
+ <h3>Redis</h3>
45
+ </div>
46
+ </div>
47
+ <div class="stats-wrapper">
39
48
  <div class="stats-container">
40
49
  <% if @redis_info.fetch("redis_version", nil) %>
41
50
  <div class="stat">
42
- <h3 class="redis_version"><%= @redis_info.fetch("redis_version") %></h3>
51
+ <h3 id="redis_version"><%= @redis_info.fetch("redis_version") %></h3>
43
52
  <p><%= t('Version') %></p>
44
53
  </div>
45
54
  <% end %>
46
55
 
47
56
  <% if @redis_info.fetch("uptime_in_days", nil) %>
48
57
  <div class="stat">
49
- <h3 class="uptime_in_days"><%= @redis_info.fetch("uptime_in_days") %></h3>
58
+ <h3 id="uptime_in_days"><%= @redis_info.fetch("uptime_in_days") %></h3>
50
59
  <p><%= t('Uptime') %></p>
51
60
  </div>
52
61
  <% end %>
53
62
 
54
63
  <% if @redis_info.fetch("connected_clients", nil) %>
55
64
  <div class="stat">
56
- <h3 class="connected_clients"><%= @redis_info.fetch("connected_clients") %></h3>
65
+ <h3 id="connected_clients"><%= @redis_info.fetch("connected_clients") %></h3>
57
66
  <p><%= t('Connections') %></p>
58
67
  </div>
59
68
  <% end %>
60
69
 
61
70
  <% if @redis_info.fetch("used_memory_human", nil) %>
62
71
  <div class="stat">
63
- <h3 class="used_memory_human"><%= @redis_info.fetch("used_memory_human") %></h3>
72
+ <h3 id="used_memory_human"><%= @redis_info.fetch("used_memory_human") %></h3>
64
73
  <p><%= t('MemoryUsage') %></p>
65
74
  </div>
66
75
  <% end %>
67
76
 
68
77
  <% if @redis_info.fetch("used_memory_peak_human", nil) %>
69
78
  <div class="stat">
70
- <h3 class="used_memory_peak_human"><%= @redis_info.fetch("used_memory_peak_human") %></h3>
79
+ <h3 id="used_memory_peak_human"><%= @redis_info.fetch("used_memory_peak_human") %></h3>
71
80
  <p><%= t('PeakMemoryUsage') %></p>
72
81
  </div>
73
82
  <% end %>
data/web/views/dead.erb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  <h3><%= t('Error') %></h3>
4
4
  <div class="table_container">
5
- <table class="error table table-bordered table-striped">
5
+ <table class="error table table-bordered table-striped table-hover">
6
6
  <tbody>
7
7
  <tr>
8
8
  <th><%= t('ErrorClass') %></th>
@@ -14,11 +14,11 @@
14
14
  <th><%= t('ErrorMessage') %></th>
15
15
  <td><%= h(@dead['error_message']) %></td>
16
16
  </tr>
17
- <% if !@dead['error_backtrace'].nil? %>
17
+ <% if @dead.error_backtrace %>
18
18
  <tr>
19
19
  <th><%= t('ErrorBacktrace') %></th>
20
20
  <td>
21
- <code><%= @dead['error_backtrace'].join("<br/>") %></code>
21
+ <code><%= @dead.error_backtrace.join("<br/>") %></code>
22
22
  </td>
23
23
  </tr>
24
24
  <% end %>
data/web/views/layout.erb CHANGED
@@ -11,16 +11,18 @@
11
11
  <% end %>
12
12
 
13
13
  <link href="<%= root_path %>stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />
14
+ <link href="<%= root_path %>stylesheets/application-dark.css" media="screen and (prefers-color-scheme: dark)" rel="stylesheet" type="text/css" />
14
15
  <% if rtl? %>
15
16
  <link href="<%= root_path %>stylesheets/application-rtl.css" media="screen" rel="stylesheet" type="text/css" />
16
17
  <% end %>
17
18
 
19
+ <link rel="apple-touch-icon" href="<%= root_path %>images/apple-touch-icon.png">
18
20
  <link rel="shortcut icon" type="image/ico" href="<%= root_path %>images/favicon.ico" />
19
21
  <script type="text/javascript" src="<%= root_path %>javascripts/application.js"></script>
20
22
  <meta name="google" content="notranslate" />
21
23
  <%= display_custom_head %>
22
24
  </head>
23
- <body class="admin" data-poll-path="<%= poll_path %>" data-locale="<%= locale %>">
25
+ <body class="admin" data-locale="<%= locale %>">
24
26
  <%= erb :_nav %>
25
27
  <div id="page">
26
28
  <div class="container">
@@ -0,0 +1,69 @@
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/metrics.js"></script>
4
+
5
+ <h2>Total execution time</h2>
6
+
7
+ <%
8
+ table_limit = 20
9
+ chart_limit = 5
10
+ job_results = @query_result.job_results.sort_by { |(kls, jr)| jr.totals["s"] }.reverse.first(table_limit)
11
+ visible_kls = job_results.first(chart_limit).map(&:first)
12
+ %>
13
+
14
+ <canvas id="job-metrics-overview-chart"></canvas>
15
+
16
+ <script>
17
+ window.jobMetricsChart = new JobMetricsOverviewChart(
18
+ "job-metrics-overview-chart",
19
+ <%= Sidekiq.dump_json({
20
+ series: job_results.map { |(kls, jr)| [kls, jr.dig("series", "s")] }.to_h,
21
+ marks: @query_result.marks.map { |m| [m.bucket, m.label] },
22
+ visible: visible_kls,
23
+ labels: @query_result.buckets,
24
+ }) %>
25
+ )
26
+ </script>
27
+
28
+ <h2>Most Time-Consuming Jobs</h2>
29
+
30
+ <div class="table_container">
31
+ <table class="table table-bordered table-striped table-hover">
32
+ <tbody>
33
+ <tr>
34
+ <th><%= t('Name') %></th>
35
+ <th><%= t('Processed') %></th>
36
+ <th><%= t('Failed') %></th>
37
+ <th><%= t('ExecutionTime') %></th>
38
+ <th><%= t('AvgExecutionTime') %></th>
39
+ </tr>
40
+ <% if job_results.any? %>
41
+ <% job_results.each_with_index do |(kls, jr), i| %>
42
+ <tr>
43
+ <td>
44
+ <div class="metrics-swatch-wrapper">
45
+ <% id = "metrics-swatch-#{kls}" %>
46
+ <input
47
+ type="checkbox"
48
+ id="<%= id %>"
49
+ class="metrics-swatch"
50
+ value="<%= kls %>"
51
+ />
52
+ <code><a href="<%= root_path %>metrics/<%= kls %>"><%= kls %></a></code>
53
+ </div>
54
+ <script>jobMetricsChart.registerSwatch("<%= id %>")</script>
55
+ </td>
56
+ <td><%= jr.dig("totals", "p") %></td>
57
+ <td><%= jr.dig("totals", "f") %></td>
58
+ <td><%= jr.dig("totals", "s").round(2) %> seconds</td>
59
+ <td><%= jr.total_avg("s").round(2) %> seconds</td>
60
+ </tr>
61
+ <% end %>
62
+ <% else %>
63
+ <tr><td colspan=5><%= t("NoDataFound") %></td></tr>
64
+ <% end %>
65
+ </tbody>
66
+ </table>
67
+ </div>
68
+
69
+ <p><small>Data from <%= @query_result.starts_at %> to <%= @query_result.ends_at %></small></p>
@@ -0,0 +1,87 @@
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/metrics.js"></script>
4
+
5
+ <%
6
+ job_result = @query_result.job_results[@name]
7
+ hist_totals = job_result.hist.values.first.zip(*job_result.hist.values[1..-1]).map(&:sum)
8
+ bucket_labels =Sidekiq::Metrics::Histogram::LABELS
9
+ bucket_intervals =Sidekiq::Metrics::Histogram::BUCKET_INTERVALS.reverse
10
+
11
+ # Replace INFINITY since it can't be represented as JSON
12
+ bucket_intervals[0] = bucket_intervals[1] * 2
13
+ %>
14
+
15
+ <% if job_result.totals["s"] > 0 %>
16
+ <div class="header-with-subheader">
17
+ <h1>
18
+ <a href="<%= root_path %>/metrics"><%= t(:metrics).to_s.titleize %></a> /
19
+ <%= h @name %>
20
+ </h1>
21
+ <h2>Histogram summary</h2>
22
+ </div>
23
+
24
+ <canvas id="hist-totals-chart"></canvas>
25
+
26
+ <script>
27
+ window.histTotalsChart = new HistTotalsChart(
28
+ "hist-totals-chart",
29
+ <%= Sidekiq.dump_json({
30
+ series: hist_totals,
31
+ labels: bucket_labels,
32
+ }) %>
33
+ )
34
+ </script>
35
+
36
+ <h2>Performance over time</h2>
37
+
38
+ <canvas id="hist-bubble-chart"></canvas>
39
+
40
+ <script>
41
+ window.histBubbleChart = new HistBubbleChart(
42
+ "hist-bubble-chart",
43
+ <%= Sidekiq.dump_json({
44
+ hist: job_result.hist,
45
+ marks: @query_result.marks.map { |m| [m.bucket, m.label] },
46
+ labels: @query_result.buckets,
47
+ histIntervals: bucket_intervals,
48
+ }) %>
49
+ )
50
+ </script>
51
+
52
+ <div class="table_container">
53
+ <table class="table table-bordered table-striped table-hover">
54
+ <tbody>
55
+ <tr>
56
+ <th><%= t('Time') %></th>
57
+ <th><%= t('Processed') %></th>
58
+ <th><%= t('Failed') %></th>
59
+ <th><%= t('ExecutionTime') %></th>
60
+ <th><%= t('AvgExecutionTime') %></th>
61
+ </tr>
62
+ <% @query_result.buckets.reverse.each do |bucket| %>
63
+ <tr>
64
+ <td><%= bucket %></td>
65
+ <td><%= job_result.series.dig("p", bucket) %></td>
66
+ <td><%= job_result.series.dig("f", bucket) %></td>
67
+ <% if (total_sec = job_result.series.dig("s", bucket)) > 0 %>
68
+ <td><%= total_sec.round(2) %> seconds</td>
69
+ <td><%= job_result.series_avg("s")[bucket].round(2) %> seconds</td>
70
+ <% else %>
71
+ <td>&mdash;</td>
72
+ <td>&mdash;</td>
73
+ <% end %>
74
+ </tr>
75
+ <% end %>
76
+ </tbody>
77
+ </table>
78
+ </div>
79
+ <p><small>Data from <%= @query_result.starts_at %> to <%= @query_result.ends_at %></small></p>
80
+ <% else %>
81
+ <h1>
82
+ <a href="<%= root_path %>/metrics"><%= t(:metrics).to_s.titleize %></a> /
83
+ <%= h @name %>
84
+ </h1>
85
+
86
+ <div class="alert alert-success"><%= t('NoJobMetricsFound') %></div>
87
+ <% end %>