sidekiq 6.1.1 → 6.5.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +250 -3
  3. data/LICENSE +3 -3
  4. data/README.md +10 -6
  5. data/bin/sidekiq +3 -3
  6. data/bin/sidekiqload +70 -66
  7. data/bin/sidekiqmon +1 -1
  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 +352 -156
  13. data/lib/sidekiq/cli.rb +86 -41
  14. data/lib/sidekiq/client.rb +49 -73
  15. data/lib/sidekiq/{util.rb → component.rb} +12 -14
  16. data/lib/sidekiq/delay.rb +3 -1
  17. data/lib/sidekiq/extensions/action_mailer.rb +3 -2
  18. data/lib/sidekiq/extensions/active_record.rb +1 -1
  19. data/lib/sidekiq/extensions/generic_proxy.rb +4 -2
  20. data/lib/sidekiq/fetch.rb +31 -20
  21. data/lib/sidekiq/job.rb +13 -0
  22. data/lib/sidekiq/job_logger.rb +16 -28
  23. data/lib/sidekiq/job_retry.rb +79 -59
  24. data/lib/sidekiq/job_util.rb +71 -0
  25. data/lib/sidekiq/launcher.rb +126 -65
  26. data/lib/sidekiq/logger.rb +11 -20
  27. data/lib/sidekiq/manager.rb +35 -34
  28. data/lib/sidekiq/metrics/deploy.rb +47 -0
  29. data/lib/sidekiq/metrics/query.rb +153 -0
  30. data/lib/sidekiq/metrics/shared.rb +94 -0
  31. data/lib/sidekiq/metrics/tracking.rb +134 -0
  32. data/lib/sidekiq/middleware/chain.rb +88 -42
  33. data/lib/sidekiq/middleware/current_attributes.rb +63 -0
  34. data/lib/sidekiq/middleware/i18n.rb +6 -4
  35. data/lib/sidekiq/middleware/modules.rb +21 -0
  36. data/lib/sidekiq/monitor.rb +2 -2
  37. data/lib/sidekiq/paginator.rb +17 -9
  38. data/lib/sidekiq/processor.rb +47 -41
  39. data/lib/sidekiq/rails.rb +32 -4
  40. data/lib/sidekiq/redis_client_adapter.rb +154 -0
  41. data/lib/sidekiq/redis_connection.rb +84 -55
  42. data/lib/sidekiq/ring_buffer.rb +29 -0
  43. data/lib/sidekiq/scheduled.rb +96 -32
  44. data/lib/sidekiq/testing/inline.rb +4 -4
  45. data/lib/sidekiq/testing.rb +38 -39
  46. data/lib/sidekiq/transaction_aware_client.rb +45 -0
  47. data/lib/sidekiq/version.rb +1 -1
  48. data/lib/sidekiq/web/action.rb +3 -3
  49. data/lib/sidekiq/web/application.rb +41 -16
  50. data/lib/sidekiq/web/csrf_protection.rb +32 -5
  51. data/lib/sidekiq/web/helpers.rb +52 -30
  52. data/lib/sidekiq/web/router.rb +4 -1
  53. data/lib/sidekiq/web.rb +38 -78
  54. data/lib/sidekiq/worker.rb +142 -16
  55. data/lib/sidekiq.rb +114 -31
  56. data/sidekiq.gemspec +12 -4
  57. data/web/assets/images/apple-touch-icon.png +0 -0
  58. data/web/assets/javascripts/application.js +114 -60
  59. data/web/assets/javascripts/chart.min.js +13 -0
  60. data/web/assets/javascripts/chartjs-plugin-annotation.min.js +7 -0
  61. data/web/assets/javascripts/dashboard.js +50 -67
  62. data/web/assets/javascripts/graph.js +16 -0
  63. data/web/assets/javascripts/metrics.js +262 -0
  64. data/web/assets/stylesheets/application-dark.css +61 -51
  65. data/web/assets/stylesheets/application-rtl.css +0 -4
  66. data/web/assets/stylesheets/application.css +84 -243
  67. data/web/locales/ar.yml +8 -2
  68. data/web/locales/el.yml +43 -19
  69. data/web/locales/en.yml +11 -1
  70. data/web/locales/es.yml +18 -2
  71. data/web/locales/fr.yml +8 -1
  72. data/web/locales/ja.yml +10 -0
  73. data/web/locales/lt.yml +1 -1
  74. data/web/locales/pt-br.yml +27 -9
  75. data/web/locales/ru.yml +4 -0
  76. data/web/locales/zh-cn.yml +36 -11
  77. data/web/locales/zh-tw.yml +32 -7
  78. data/web/views/_footer.erb +1 -1
  79. data/web/views/_job_info.erb +1 -1
  80. data/web/views/_nav.erb +1 -1
  81. data/web/views/_poll_link.erb +2 -5
  82. data/web/views/_summary.erb +7 -7
  83. data/web/views/busy.erb +57 -21
  84. data/web/views/dashboard.erb +23 -14
  85. data/web/views/dead.erb +1 -1
  86. data/web/views/layout.erb +2 -1
  87. data/web/views/metrics.erb +69 -0
  88. data/web/views/metrics_for_job.erb +87 -0
  89. data/web/views/morgue.erb +6 -6
  90. data/web/views/queue.erb +15 -11
  91. data/web/views/queues.erb +4 -4
  92. data/web/views/retries.erb +7 -7
  93. data/web/views/retry.erb +1 -1
  94. data/web/views/scheduled.erb +1 -1
  95. metadata +52 -39
  96. data/.circleci/config.yml +0 -71
  97. data/.github/contributing.md +0 -32
  98. data/.github/issue_template.md +0 -11
  99. data/.gitignore +0 -13
  100. data/.standard.yml +0 -20
  101. data/3.0-Upgrade.md +0 -70
  102. data/4.0-Upgrade.md +0 -53
  103. data/5.0-Upgrade.md +0 -56
  104. data/6.0-Upgrade.md +0 -72
  105. data/COMM-LICENSE +0 -97
  106. data/Ent-2.0-Upgrade.md +0 -37
  107. data/Ent-Changes.md +0 -275
  108. data/Gemfile +0 -24
  109. data/Gemfile.lock +0 -208
  110. data/Pro-2.0-Upgrade.md +0 -138
  111. data/Pro-3.0-Upgrade.md +0 -44
  112. data/Pro-4.0-Upgrade.md +0 -35
  113. data/Pro-5.0-Upgrade.md +0 -25
  114. data/Pro-Changes.md +0 -795
  115. data/Rakefile +0 -10
  116. data/code_of_conduct.md +0 -50
  117. data/lib/generators/sidekiq/worker_generator.rb +0 -57
  118. data/lib/sidekiq/exception_handler.rb +0 -27
@@ -0,0 +1,262 @@
1
+ if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
2
+ Chart.defaults.borderColor = "#333"
3
+ Chart.defaults.color = "#aaa"
4
+ }
5
+
6
+ class BaseChart {
7
+ constructor(id, options) {
8
+ this.ctx = document.getElementById(id);
9
+ this.options = options
10
+ this.fallbackColor = "#999";
11
+ this.colors = [
12
+ // Colors taken from https://www.chartjs.org/docs/latest/samples/utils.html
13
+ "#537bc4",
14
+ "#4dc9f6",
15
+ "#f67019",
16
+ "#f53794",
17
+ "#acc236",
18
+ "#166a8f",
19
+ "#00a950",
20
+ "#58595b",
21
+ "#8549ba",
22
+ "#991b1b",
23
+ ];
24
+
25
+ this.chart = new Chart(this.ctx, {
26
+ type: this.options.chartType,
27
+ data: { labels: this.options.labels, datasets: this.datasets },
28
+ options: this.chartOptions,
29
+ });
30
+ }
31
+
32
+ addMarksToChart() {
33
+ this.options.marks.forEach(([bucket, label], i) => {
34
+ this.chart.options.plugins.annotation.annotations[`deploy-${i}`] = {
35
+ type: "line",
36
+ xMin: bucket,
37
+ xMax: bucket,
38
+ borderColor: "rgba(220, 38, 38, 0.4)",
39
+ borderWidth: 2,
40
+ };
41
+ });
42
+ }
43
+ }
44
+
45
+ class JobMetricsOverviewChart extends BaseChart {
46
+ constructor(id, options) {
47
+ super(id, { ...options, chartType: "line" });
48
+ this.swatches = [];
49
+
50
+ this.addMarksToChart();
51
+ this.chart.update();
52
+ }
53
+
54
+ registerSwatch(id) {
55
+ const el = document.getElementById(id);
56
+ el.onchange = () => this.toggle(el.value, el.checked);
57
+ this.swatches[el.value] = el;
58
+ this.updateSwatch(el.value);
59
+ }
60
+
61
+ updateSwatch(kls) {
62
+ const el = this.swatches[kls];
63
+ const ds = this.chart.data.datasets.find((ds) => ds.label == kls);
64
+ el.checked = !!ds;
65
+ el.style.color = ds ? ds.borderColor : null;
66
+ }
67
+
68
+ toggle(kls, visible) {
69
+ if (visible) {
70
+ this.chart.data.datasets.push(this.dataset(kls));
71
+ } else {
72
+ const i = this.chart.data.datasets.findIndex((ds) => ds.label == kls);
73
+ this.colors.unshift(this.chart.data.datasets[i].borderColor);
74
+ this.chart.data.datasets.splice(i, 1);
75
+ }
76
+
77
+ this.updateSwatch(kls);
78
+ this.chart.update();
79
+ }
80
+
81
+ dataset(kls) {
82
+ const color = this.colors.shift() || this.fallbackColor;
83
+
84
+ return {
85
+ label: kls,
86
+ data: this.options.series[kls],
87
+ borderColor: color,
88
+ backgroundColor: color,
89
+ borderWidth: 2,
90
+ pointRadius: 2,
91
+ };
92
+ }
93
+
94
+ get datasets() {
95
+ return Object.entries(this.options.series)
96
+ .filter(([kls, _]) => this.options.visible.includes(kls))
97
+ .map(([kls, _]) => this.dataset(kls));
98
+ }
99
+
100
+ get chartOptions() {
101
+ return {
102
+ aspectRatio: 4,
103
+ scales: {
104
+ y: {
105
+ beginAtZero: true,
106
+ title: {
107
+ text: "Total execution time (sec)",
108
+ display: true,
109
+ },
110
+ },
111
+ },
112
+ interaction: {
113
+ mode: "x",
114
+ },
115
+ plugins: {
116
+ legend: {
117
+ display: false,
118
+ },
119
+ tooltip: {
120
+ callbacks: {
121
+ title: (items) => `${items[0].label} UTC`,
122
+ label: (item) =>
123
+ `${item.dataset.label}: ${item.parsed.y.toFixed(1)} seconds`,
124
+ footer: (items) => {
125
+ const bucket = items[0].label;
126
+ const marks = this.options.marks.filter(([b, _]) => b == bucket);
127
+ return marks.map(([b, msg]) => `Deploy: ${msg}`);
128
+ },
129
+ },
130
+ },
131
+ },
132
+ };
133
+ }
134
+ }
135
+
136
+ class HistTotalsChart extends BaseChart {
137
+ constructor(id, options) {
138
+ super(id, { ...options, chartType: "bar" });
139
+ }
140
+
141
+ get datasets() {
142
+ return [{
143
+ data: this.options.series,
144
+ backgroundColor: this.colors[0],
145
+ borderWidth: 0,
146
+ }];
147
+ }
148
+
149
+ get chartOptions() {
150
+ return {
151
+ aspectRatio: 6,
152
+ scales: {
153
+ y: {
154
+ beginAtZero: true,
155
+ title: {
156
+ text: "Total jobs",
157
+ display: true,
158
+ },
159
+ },
160
+ },
161
+ interaction: {
162
+ mode: "x",
163
+ },
164
+ plugins: {
165
+ legend: {
166
+ display: false,
167
+ },
168
+ tooltip: {
169
+ callbacks: {
170
+ label: (item) => `${item.parsed.y} jobs`,
171
+ },
172
+ },
173
+ },
174
+ };
175
+ }
176
+ }
177
+
178
+ class HistBubbleChart extends BaseChart {
179
+ constructor(id, options) {
180
+ super(id, { ...options, chartType: "bubble" });
181
+
182
+ this.addMarksToChart();
183
+ this.chart.update();
184
+ }
185
+
186
+ get datasets() {
187
+ const data = [];
188
+ let maxCount = 0;
189
+
190
+ Object.entries(this.options.hist).forEach(([bucket, hist]) => {
191
+ hist.forEach((count, histBucket) => {
192
+ if (count > 0) {
193
+ data.push({
194
+ x: bucket,
195
+ // histogram data is ordered fastest to slowest, but this.histIntervals is
196
+ // slowest to fastest (so it displays correctly on the chart).
197
+ y:
198
+ this.options.histIntervals[this.options.histIntervals.length - 1 - histBucket] /
199
+ 1000,
200
+ count: count,
201
+ });
202
+
203
+ if (count > maxCount) maxCount = count;
204
+ }
205
+ });
206
+ });
207
+
208
+ // Chart.js will not calculate the bubble size. We have to do that.
209
+ const maxRadius = this.ctx.offsetWidth / this.options.labels.length;
210
+ const minRadius = 1
211
+ const multiplier = (maxRadius / maxCount) * 1.5;
212
+ data.forEach((entry) => {
213
+ entry.r = entry.count * multiplier + minRadius;
214
+ });
215
+
216
+ return [{
217
+ data: data,
218
+ backgroundColor: "#537bc4",
219
+ borderColor: "#537bc4",
220
+ }];
221
+ }
222
+
223
+ get chartOptions() {
224
+ return {
225
+ aspectRatio: 3,
226
+ scales: {
227
+ x: {
228
+ type: "category",
229
+ labels: this.options.labels,
230
+ },
231
+ y: {
232
+ title: {
233
+ text: "Execution time (sec)",
234
+ display: true,
235
+ },
236
+ },
237
+ },
238
+ interaction: {
239
+ mode: "x",
240
+ },
241
+ plugins: {
242
+ legend: {
243
+ display: false,
244
+ },
245
+ tooltip: {
246
+ callbacks: {
247
+ title: (items) => `${items[0].raw.x} UTC`,
248
+ label: (item) =>
249
+ `${item.parsed.y} seconds: ${item.raw.count} job${
250
+ item.raw.count == 1 ? "" : "s"
251
+ }`,
252
+ footer: (items) => {
253
+ const bucket = items[0].raw.x;
254
+ const marks = this.options.marks.filter(([b, _]) => b == bucket);
255
+ return marks.map(([b, msg]) => `Deploy: ${msg}`);
256
+ },
257
+ },
258
+ },
259
+ },
260
+ };
261
+ }
262
+ }
@@ -1,34 +1,44 @@
1
1
  html, body {
2
- background-color: #070707 !important;
3
- color: #ccc;
2
+ background-color: #171717 !important;
3
+ color: #DEDEDE;
4
4
  }
5
5
 
6
6
  a,
7
7
  .title,
8
8
  .summary_bar ul .count,
9
+ span.current-interval,
9
10
  .navbar .navbar-brand {
10
- color: #af0014;
11
+ color: #d04;
12
+ }
13
+
14
+ .history-graph.active,
15
+ .beacon .dot {
16
+ background-color: #d04;
11
17
  }
12
18
 
13
19
  .navbar .navbar-brand:hover {
14
- color: #ccc;
20
+ color: #ddd;
15
21
  }
16
22
 
17
23
  .navbar .navbar-brand .status {
18
- color: #ccc;
24
+ color: #ddd;
25
+ }
26
+
27
+ .navbar-default .navbar-nav > li > a {
28
+ color: #ddd;
19
29
  }
20
30
 
21
31
  .navbar-inverse {
22
- background-color: #000;
23
- border-color: #333;
32
+ background-color: #222;
33
+ border-color: #444;
24
34
  }
25
35
 
26
- table.table-white {
27
- background-color: #111;
36
+ table {
37
+ background-color: #1D1D1D;
28
38
  }
29
39
 
30
40
  .table-striped > tbody > tr:nth-of-type(odd) {
31
- background-color: #222;
41
+ background-color: #2E2E2E;
32
42
  }
33
43
 
34
44
  .table-bordered,
@@ -38,64 +48,67 @@ table.table-white {
38
48
  .table-bordered > tfoot > tr > th,
39
49
  .table-bordered > thead > tr > td,
40
50
  .table-bordered > thead > tr > th {
41
- border: 1px solid #333;
51
+ border: 1px solid #444;
42
52
  }
43
53
 
44
54
  .table-hover > tbody > tr:hover {
45
- background-color: #333;
55
+ background-color: #444;
46
56
  }
47
57
 
48
58
  .alert {
49
59
  border: none;
50
- color: #ccc;
60
+ color: #ddd;
51
61
  }
52
62
 
53
63
  .alert-success {
54
- background-color: #182d11;
64
+ background-color: #484;
55
65
  }
56
66
 
57
- a:link,
58
- a:active,
59
- a:hover,
60
- a:visited {
61
- color: #63798c;
67
+ .alert-danger {
68
+ background-color: #980035;
62
69
  }
63
70
 
64
- a.btn {
65
- color: #000;
71
+ .alert-info {
72
+ background-color: #31708f;
66
73
  }
67
74
 
68
- .summary_bar .summary {
69
- background-color: #111;
70
- border: 1px solid #333;
75
+ a:link, a:active, a:hover, a:visited {
76
+ color: #ddd;
77
+ }
71
78
 
72
- -webkit-box-shadow: 0 0 5px rgba(255, 255, 255, 0.1);
73
- -moz-box-shadow: 0 0 5px rgba(255, 255, 255, 0.1);
74
- box-shadow: 0 0 5px rgba(255, 255, 255, 0.1);
79
+ input {
80
+ background-color: #444;
81
+ color: #ccc;
82
+ padding: 3px;
83
+ }
84
+
85
+ .summary_bar .summary {
86
+ background-color: #232323;
87
+ border: 1px solid #444;
75
88
  }
76
89
 
77
90
  .navbar-default {
78
- background-color: #000;
79
- border-color: #3d3d3d;
91
+ background-color: #0F0F0F;
92
+ border-color: #444;
80
93
  }
81
94
 
82
95
  .navbar-default .navbar-nav > .active > a,
83
96
  .navbar-default .navbar-nav > .active > a:focus,
84
97
  .navbar-default .navbar-nav > .active > a:hover {
85
- color: #ccc;
86
- background-color: #282828;
98
+ color: #ddd;
99
+ background-color: #333;
87
100
  }
88
101
 
89
102
  .navbar-default .navbar-nav > li > a:hover {
90
- color: #ccc;
103
+ color: #ddd;
91
104
  }
92
105
 
93
106
  .pagination > li > a,
94
107
  .pagination > li > a:hover,
95
108
  .pagination > li > span {
96
- color: #ccc;
97
- background-color: #282828;
98
- border-color: #353535;
109
+ color: #ddd;
110
+ background-color: #333;
111
+ border-color: #444;
99
112
  }
100
113
  .pagination > .disabled > a,
101
114
  .pagination > .disabled > a:focus,
@@ -103,31 +116,28 @@ a.btn {
103
116
  .pagination > .disabled > span,
104
117
  .pagination > .disabled > span:focus,
105
118
  .pagination > .disabled > span:hover {
106
- color: #a5a5a5;
107
- background-color: #282828;
108
- border-color: #353535;
119
+ color: #ddd;
120
+ background-color: #333;
121
+ border-color: #444;
109
122
  }
110
123
 
111
124
  .stat {
112
- border: 1px solid rgba(255, 255, 255, 0.1);
113
- }
114
-
115
- #live-poll {
116
- color: #ccc;
117
- }
118
-
119
- .btn-warn {
120
- color: #333;
125
+ border: 1px solid #888;
121
126
  }
122
127
 
123
128
  .rickshaw_graph .detail {
124
- background: rgba(255, 255, 255, .1)
129
+ background: #888;
125
130
  }
126
131
  .rickshaw_graph .x_tick {
127
- border-color: rgba(255, 255, 255, .2);
132
+ border-color: #888;
128
133
  }
129
134
 
130
135
  .rickshaw_graph .y_ticks.glow text {
131
- fill: #ccc;
132
- color: #ccc;
136
+ fill: #ddd;
137
+ color: #ddd;
138
+ }
139
+
140
+ .info-circle {
141
+ color: #222;
142
+ background-color: #888;
133
143
  }
@@ -46,10 +46,6 @@ form .btn-group .btn {
46
46
  .navbar .poll-wrapper {
47
47
  margin: 4px 0 0 4px;
48
48
  }
49
-
50
- .navbar .dropdown-menu a {
51
- text-align: right;
52
- }
53
49
  }
54
50
 
55
51
  .navbar-footer .navbar ul.nav a.navbar-brand {