sidekiq 6.5.7 → 7.0.0

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.

Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +20 -4
  3. data/{LICENSE → LICENSE.txt} +0 -0
  4. data/README.md +13 -12
  5. data/bin/sidekiq +3 -8
  6. data/bin/sidekiqload +15 -24
  7. data/lib/sidekiq/api.rb +51 -120
  8. data/lib/sidekiq/capsule.rb +110 -0
  9. data/lib/sidekiq/cli.rb +52 -60
  10. data/lib/sidekiq/client.rb +29 -16
  11. data/lib/sidekiq/component.rb +1 -0
  12. data/lib/sidekiq/config.rb +271 -0
  13. data/lib/sidekiq/deploy.rb +62 -0
  14. data/lib/sidekiq/embedded.rb +61 -0
  15. data/lib/sidekiq/fetch.rb +10 -11
  16. data/lib/sidekiq/job.rb +375 -10
  17. data/lib/sidekiq/job_logger.rb +1 -1
  18. data/lib/sidekiq/job_retry.rb +8 -8
  19. data/lib/sidekiq/job_util.rb +4 -4
  20. data/lib/sidekiq/launcher.rb +36 -46
  21. data/lib/sidekiq/logger.rb +1 -26
  22. data/lib/sidekiq/manager.rb +9 -11
  23. data/lib/sidekiq/metrics/query.rb +2 -2
  24. data/lib/sidekiq/metrics/shared.rb +4 -3
  25. data/lib/sidekiq/metrics/tracking.rb +18 -18
  26. data/lib/sidekiq/middleware/chain.rb +7 -9
  27. data/lib/sidekiq/middleware/current_attributes.rb +8 -13
  28. data/lib/sidekiq/paginator.rb +8 -0
  29. data/lib/sidekiq/processor.rb +17 -26
  30. data/lib/sidekiq/rails.rb +2 -8
  31. data/lib/sidekiq/redis_client_adapter.rb +9 -45
  32. data/lib/sidekiq/redis_connection.rb +11 -111
  33. data/lib/sidekiq/scheduled.rb +19 -20
  34. data/lib/sidekiq/testing.rb +5 -33
  35. data/lib/sidekiq/transaction_aware_client.rb +4 -5
  36. data/lib/sidekiq/version.rb +2 -1
  37. data/lib/sidekiq/web/application.rb +4 -1
  38. data/lib/sidekiq/web/csrf_protection.rb +1 -1
  39. data/lib/sidekiq/web/helpers.rb +8 -29
  40. data/lib/sidekiq/web.rb +2 -17
  41. data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
  42. data/lib/sidekiq.rb +76 -274
  43. data/sidekiq.gemspec +29 -5
  44. data/web/assets/javascripts/base-charts.js +106 -0
  45. data/web/assets/javascripts/dashboard-charts.js +166 -0
  46. data/web/assets/javascripts/dashboard.js +3 -223
  47. data/web/assets/javascripts/metrics.js +90 -116
  48. data/web/assets/stylesheets/application-rtl.css +2 -91
  49. data/web/assets/stylesheets/application.css +21 -296
  50. data/web/locales/ar.yml +70 -70
  51. data/web/locales/cs.yml +62 -62
  52. data/web/locales/da.yml +52 -52
  53. data/web/locales/de.yml +65 -65
  54. data/web/locales/el.yml +2 -7
  55. data/web/locales/en.yml +76 -70
  56. data/web/locales/es.yml +68 -68
  57. data/web/locales/fa.yml +65 -65
  58. data/web/locales/fr.yml +67 -67
  59. data/web/locales/he.yml +65 -64
  60. data/web/locales/hi.yml +59 -59
  61. data/web/locales/it.yml +53 -53
  62. data/web/locales/ja.yml +64 -68
  63. data/web/locales/ko.yml +52 -52
  64. data/web/locales/lt.yml +66 -66
  65. data/web/locales/nb.yml +61 -61
  66. data/web/locales/nl.yml +52 -52
  67. data/web/locales/pl.yml +45 -45
  68. data/web/locales/pt-br.yml +59 -69
  69. data/web/locales/pt.yml +51 -51
  70. data/web/locales/ru.yml +67 -66
  71. data/web/locales/sv.yml +53 -53
  72. data/web/locales/ta.yml +60 -60
  73. data/web/locales/uk.yml +62 -61
  74. data/web/locales/ur.yml +64 -64
  75. data/web/locales/vi.yml +67 -67
  76. data/web/locales/zh-cn.yml +1 -0
  77. data/web/locales/zh-tw.yml +10 -1
  78. data/web/views/_footer.erb +5 -2
  79. data/web/views/busy.erb +6 -1
  80. data/web/views/dashboard.erb +36 -5
  81. data/web/views/metrics.erb +30 -19
  82. data/web/views/metrics_for_job.erb +16 -34
  83. metadata +56 -28
  84. data/lib/sidekiq/delay.rb +0 -43
  85. data/lib/sidekiq/extensions/action_mailer.rb +0 -48
  86. data/lib/sidekiq/extensions/active_record.rb +0 -43
  87. data/lib/sidekiq/extensions/class_methods.rb +0 -43
  88. data/lib/sidekiq/extensions/generic_proxy.rb +0 -33
  89. data/lib/sidekiq/metrics/deploy.rb +0 -47
  90. data/lib/sidekiq/worker.rb +0 -370
  91. data/web/assets/javascripts/graph.js +0 -16
@@ -1,85 +1,54 @@
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
- ];
1
+ class JobMetricsOverviewChart extends BaseChart {
2
+ constructor(el, options) {
3
+ super(el, { ...options, chartType: "line" });
4
+ this.swatches = [];
5
+ this.visibleKls = options.visibleKls;
24
6
 
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
- });
7
+ this.init();
30
8
  }
31
9
 
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
- });
10
+ get datasets() {
11
+ return Object.entries(this.options.series)
12
+ .filter(([kls, _]) => this.visibleKls.includes(kls))
13
+ .map(([kls, _]) => this.buildDataset(kls));
42
14
  }
43
- }
44
15
 
45
- class JobMetricsOverviewChart extends BaseChart {
46
- constructor(id, options) {
47
- super(id, { ...options, chartType: "line" });
48
- this.swatches = [];
16
+ get metric() {
17
+ return this._metric || this.options.initialMetric;
18
+ }
49
19
 
50
- this.addMarksToChart();
51
- this.chart.update();
20
+ set metric(m) {
21
+ this._metric = m;
52
22
  }
53
23
 
54
24
  registerSwatch(id) {
55
25
  const el = document.getElementById(id);
56
- el.onchange = () => this.toggle(el.value, el.checked);
26
+ el.addEventListener("change", () => this.toggleKls(el.value, el.checked));
57
27
  this.swatches[el.value] = el;
58
- this.updateSwatch(el.value);
28
+ this.updateSwatch(el.value, el.checked);
59
29
  }
60
30
 
61
- updateSwatch(kls) {
31
+ updateSwatch(kls, checked) {
62
32
  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;
33
+ el.checked = checked;
34
+ el.style.color = this.colors.assignments[kls] || "";
66
35
  }
67
36
 
68
- toggle(kls, visible) {
37
+ toggleKls(kls, visible) {
69
38
  if (visible) {
70
- this.chart.data.datasets.push(this.dataset(kls));
39
+ this.chart.data.datasets.push(this.buildDataset(kls));
71
40
  } else {
72
41
  const i = this.chart.data.datasets.findIndex((ds) => ds.label == kls);
73
- this.colors.unshift(this.chart.data.datasets[i].borderColor);
42
+ this.colors.checkIn(kls);
74
43
  this.chart.data.datasets.splice(i, 1);
75
44
  }
76
45
 
77
- this.updateSwatch(kls);
78
- this.chart.update();
46
+ this.updateSwatch(kls, visible);
47
+ this.update();
79
48
  }
80
49
 
81
- dataset(kls) {
82
- const color = this.colors.shift() || this.fallbackColor;
50
+ buildDataset(kls) {
51
+ const color = this.colors.checkOut(kls);
83
52
 
84
53
  return {
85
54
  label: kls,
@@ -91,40 +60,36 @@ class JobMetricsOverviewChart extends BaseChart {
91
60
  };
92
61
  }
93
62
 
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
63
  get chartOptions() {
101
64
  return {
65
+ ...super.chartOptions,
102
66
  aspectRatio: 4,
103
67
  scales: {
68
+ ...super.chartOptions.scales,
104
69
  y: {
70
+ ...super.chartOptions.scales.y,
105
71
  beginAtZero: true,
106
72
  title: {
107
- text: "Total execution time (sec)",
73
+ text: this.options.yLabel,
108
74
  display: true,
109
75
  },
110
76
  },
111
77
  },
112
- interaction: {
113
- mode: "x",
114
- },
115
78
  plugins: {
116
- legend: {
117
- display: false,
118
- },
79
+ ...super.chartOptions.plugins,
119
80
  tooltip: {
81
+ ...super.chartOptions.plugins.tooltip,
120
82
  callbacks: {
121
83
  title: (items) => `${items[0].label} UTC`,
122
84
  label: (item) =>
123
- `${item.dataset.label}: ${item.parsed.y.toFixed(1)} seconds`,
85
+ `${item.dataset.label}: ${item.parsed.y.toFixed(1)} ` +
86
+ `${this.options.units}`,
124
87
  footer: (items) => {
125
88
  const bucket = items[0].label;
126
89
  const marks = this.options.marks.filter(([b, _]) => b == bucket);
127
- return marks.map(([b, msg]) => `Deploy: ${msg}`);
90
+ return marks.map(
91
+ ([b, msg]) => `${this.options.markLabel}: ${msg}`
92
+ );
128
93
  },
129
94
  },
130
95
  },
@@ -134,40 +99,49 @@ class JobMetricsOverviewChart extends BaseChart {
134
99
  }
135
100
 
136
101
  class HistTotalsChart extends BaseChart {
137
- constructor(id, options) {
138
- super(id, { ...options, chartType: "bar" });
102
+ constructor(el, options) {
103
+ super(el, { ...options, chartType: "bar" });
104
+ this.init();
139
105
  }
140
106
 
141
107
  get datasets() {
142
- return [{
143
- data: this.options.series,
144
- backgroundColor: this.colors[0],
145
- borderWidth: 0,
146
- }];
108
+ return [
109
+ {
110
+ data: this.options.series,
111
+ backgroundColor: this.colors.primary,
112
+ borderWidth: 0,
113
+ },
114
+ ];
147
115
  }
148
116
 
149
117
  get chartOptions() {
150
118
  return {
119
+ ...super.chartOptions,
151
120
  aspectRatio: 6,
152
121
  scales: {
122
+ ...super.chartOptions.scales,
153
123
  y: {
124
+ ...super.chartOptions.scales.y,
154
125
  beginAtZero: true,
155
126
  title: {
156
- text: "Total jobs",
127
+ text: this.options.yLabel,
128
+ display: true,
129
+ },
130
+ },
131
+ x: {
132
+ ...super.chartOptions.scales.x,
133
+ title: {
134
+ text: this.options.xLabel,
157
135
  display: true,
158
136
  },
159
137
  },
160
- },
161
- interaction: {
162
- mode: "x",
163
138
  },
164
139
  plugins: {
165
- legend: {
166
- display: false,
167
- },
140
+ ...super.chartOptions.plugins,
168
141
  tooltip: {
142
+ ...super.chartOptions.plugins.tooltip,
169
143
  callbacks: {
170
- label: (item) => `${item.parsed.y} jobs`,
144
+ label: (item) => `${item.parsed.y} ${this.options.units}`,
171
145
  },
172
146
  },
173
147
  },
@@ -176,11 +150,9 @@ class HistTotalsChart extends BaseChart {
176
150
  }
177
151
 
178
152
  class HistBubbleChart extends BaseChart {
179
- constructor(id, options) {
180
- super(id, { ...options, chartType: "bubble" });
181
-
182
- this.addMarksToChart();
183
- this.chart.update();
153
+ constructor(el, options) {
154
+ super(el, { ...options, chartType: "bubble" });
155
+ this.init();
184
156
  }
185
157
 
186
158
  get datasets() {
@@ -190,13 +162,13 @@ class HistBubbleChart extends BaseChart {
190
162
  Object.entries(this.options.hist).forEach(([bucket, hist]) => {
191
163
  hist.forEach((count, histBucket) => {
192
164
  if (count > 0) {
165
+ // histogram data is ordered fastest to slowest, but this.histIntervals is
166
+ // slowest to fastest (so it displays correctly on the chart).
167
+ const index = this.options.histIntervals.length - 1 - histBucket;
168
+
193
169
  data.push({
194
170
  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,
171
+ y: this.options.histIntervals[index] / 1000,
200
172
  count: count,
201
173
  });
202
174
 
@@ -206,53 +178,55 @@ class HistBubbleChart extends BaseChart {
206
178
  });
207
179
 
208
180
  // 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
181
+ const maxRadius = this.el.offsetWidth / this.options.labels.length;
182
+ const minRadius = 1;
211
183
  const multiplier = (maxRadius / maxCount) * 1.5;
212
184
  data.forEach((entry) => {
213
185
  entry.r = entry.count * multiplier + minRadius;
214
186
  });
215
187
 
216
- return [{
217
- data: data,
218
- backgroundColor: "#537bc4",
219
- borderColor: "#537bc4",
220
- }];
188
+ return [
189
+ {
190
+ data: data,
191
+ backgroundColor: this.colors.primary,
192
+ borderColor: this.colors.primary,
193
+ },
194
+ ];
221
195
  }
222
196
 
223
197
  get chartOptions() {
224
198
  return {
199
+ ...super.chartOptions,
225
200
  aspectRatio: 3,
226
201
  scales: {
202
+ ...super.chartOptions.scales,
227
203
  x: {
204
+ ...super.chartOptions.scales.x,
228
205
  type: "category",
229
206
  labels: this.options.labels,
230
207
  },
231
208
  y: {
209
+ ...super.chartOptions.scales.y,
232
210
  title: {
233
- text: "Execution time (sec)",
211
+ text: this.options.yLabel,
234
212
  display: true,
235
213
  },
236
214
  },
237
215
  },
238
- interaction: {
239
- mode: "x",
240
- },
241
216
  plugins: {
242
- legend: {
243
- display: false,
244
- },
217
+ ...super.chartOptions.plugins,
245
218
  tooltip: {
219
+ ...super.chartOptions.plugins.tooltip,
246
220
  callbacks: {
247
221
  title: (items) => `${items[0].raw.x} UTC`,
248
222
  label: (item) =>
249
- `${item.parsed.y} seconds: ${item.raw.count} job${
250
- item.raw.count == 1 ? "" : "s"
251
- }`,
223
+ `${item.parsed.y} ${this.options.yUnits}: ${item.raw.count} ${this.options.zUnits}`,
252
224
  footer: (items) => {
253
225
  const bucket = items[0].raw.x;
254
226
  const marks = this.options.marks.filter(([b, _]) => b == bucket);
255
- return marks.map(([b, msg]) => `Deploy: ${msg}`);
227
+ return marks.map(
228
+ ([b, msg]) => `${this.options.markLabel}: ${msg}`
229
+ );
256
230
  },
257
231
  },
258
232
  },
@@ -102,22 +102,8 @@ div.interval-slider {
102
102
  float: left;
103
103
  }
104
104
 
105
- #realtime-legend,
106
- #history-legend {
107
- text-align: right;
108
- float: left;
109
- }
110
- #realtime-legend .timestamp,
111
- #history-legend .timestamp {
112
- text-align: left;
113
- }
114
- #realtime-legend .line,
115
- #history-legend .line {
116
- margin: 0 20px 0 0;
117
- }
118
- #realtime-legend .swatch,
119
- #history-legend .swatch {
120
- margin: 0 0 0 8px;
105
+ #realtime-legend {
106
+ justify-content: start;
121
107
  }
122
108
 
123
109
  /* Beacon
@@ -165,78 +151,3 @@ div.interval-slider {
165
151
  padding-left: 5px;
166
152
  }
167
153
  }
168
-
169
- /* Rickshaw */
170
-
171
- .rickshaw_graph .detail .x_label.left {
172
- right: 0
173
- }
174
- .rickshaw_graph .detail .x_label.right {
175
- left: 0
176
- }
177
- .rickshaw_graph .detail .item.left {
178
- right: 0
179
- }
180
- .rickshaw_graph .detail .item.right {
181
- left: 0
182
- }
183
- .rickshaw_graph .detail .item.left:after {
184
- left: 0;
185
- right: -5px;
186
- border-right-color: unset;
187
- border-left-color: rgba(0, 0, 0, .8);
188
- border-right-width: 0;
189
- border-left-width: unset;
190
- }
191
- .rickshaw_graph .detail .item.right:after {
192
- right: 0;
193
- left: -5px;
194
- border-left-color: unset;
195
- border-right-color: rgba(0, 0, 0, .8);
196
- border-left-width: 0;
197
- border-right-width: unset;
198
- }
199
- .rickshaw_graph .detail .dot {
200
- margin-right: -3px;
201
- margin-left: unset;
202
- }
203
- .rickshaw_graph .x_tick {
204
- border-left: unset;
205
- border-right: 1px dotted rgba(0, 0, 0, .2);
206
- }
207
- .rickshaw_graph .x_tick .title {
208
- margin-right: 3px;
209
- margin-left: unset;
210
- }
211
- .rickshaw_annotation_timeline .annotation {
212
- margin-right: -2px;
213
- margin-left: unset;
214
- }
215
- .rickshaw_graph .annotation_line {
216
- border-right: 2px solid rgba(0, 0, 0, .3);
217
- border-left: unset;
218
- }
219
- .rickshaw_annotation_timeline .annotation .content {
220
- left: unset;
221
- right: -11px;
222
- }
223
- .rickshaw_graph .x_tick.glow .title,
224
- .rickshaw_graph .y_ticks.glow text {
225
- text-shadow: 1px 1px 0 rgba(255, 255, 255, .1), -1px -1px 0 rgba(255, 255, 255, .1), -1px 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1), 0 -1px 0 rgba(255, 255, 255, .1), -1px 0 0 rgba(255, 255, 255, .1), 1px 0 0 rgba(255, 255, 255, .1), 1px -1px 0 rgba(255, 255, 255, .1)
226
- }
227
- .rickshaw_graph .x_tick.inverse .title,
228
- .rickshaw_graph .y_ticks.inverse text {
229
- text-shadow: 1px 1px 0 rgba(0, 0, 0, .8), -1px -1px 0 rgba(0, 0, 0, .8), -1px 1px 0 rgba(0, 0, 0, .8), 0 1px 0 rgba(0, 0, 0, .8), 0 -1px 0 rgba(0, 0, 0, .8), -1px 0 0 rgba(0, 0, 0, .8), 1px 0 0 rgba(0, 0, 0, .8), 1px -1px 0 rgba(0, 0, 0, .8)
230
- }
231
- .rickshaw_legend .line {
232
- padding-left: 15px;
233
- padding-right: unset;
234
- }
235
- .rickshaw_legend .line .swatch {
236
- margin-left: 3px;
237
- margin-right: unset;
238
- }
239
- .rickshaw_legend .action {
240
- margin-left: .2em;
241
- margin-right: unset;
242
- }