sidekiq 6.0.0 → 6.0.2

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +21 -0
  3. data/6.0-Upgrade.md +3 -1
  4. data/Changes.md +82 -1
  5. data/Ent-Changes.md +6 -0
  6. data/Gemfile.lock +3 -3
  7. data/Pro-Changes.md +9 -1
  8. data/README.md +3 -1
  9. data/bin/sidekiqload +8 -4
  10. data/bin/sidekiqmon +4 -5
  11. data/lib/generators/sidekiq/worker_generator.rb +10 -0
  12. data/lib/sidekiq/api.rb +104 -63
  13. data/lib/sidekiq/cli.rb +18 -16
  14. data/lib/sidekiq/client.rb +8 -2
  15. data/lib/sidekiq/fetch.rb +7 -7
  16. data/lib/sidekiq/job_logger.rb +11 -3
  17. data/lib/sidekiq/job_retry.rb +21 -8
  18. data/lib/sidekiq/launcher.rb +1 -3
  19. data/lib/sidekiq/logger.rb +107 -11
  20. data/lib/sidekiq/middleware/chain.rb +11 -2
  21. data/lib/sidekiq/monitor.rb +1 -16
  22. data/lib/sidekiq/paginator.rb +7 -2
  23. data/lib/sidekiq/processor.rb +17 -19
  24. data/lib/sidekiq/scheduled.rb +13 -12
  25. data/lib/sidekiq/testing.rb +12 -0
  26. data/lib/sidekiq/util.rb +0 -2
  27. data/lib/sidekiq/version.rb +1 -1
  28. data/lib/sidekiq/web/application.rb +8 -13
  29. data/lib/sidekiq/web/helpers.rb +22 -10
  30. data/lib/sidekiq/worker.rb +4 -4
  31. data/lib/sidekiq.rb +8 -0
  32. data/sidekiq.gemspec +1 -1
  33. data/web/assets/javascripts/dashboard.js +2 -2
  34. data/web/assets/stylesheets/application-dark.css +125 -0
  35. data/web/assets/stylesheets/application.css +9 -0
  36. data/web/locales/de.yml +14 -2
  37. data/web/views/_job_info.erb +2 -1
  38. data/web/views/busy.erb +4 -1
  39. data/web/views/dead.erb +2 -2
  40. data/web/views/layout.erb +1 -0
  41. data/web/views/morgue.erb +4 -1
  42. data/web/views/queue.erb +10 -1
  43. data/web/views/retries.erb +4 -1
  44. data/web/views/retry.erb +2 -2
  45. data/web/views/scheduled.erb +4 -1
  46. metadata +5 -4
@@ -5,7 +5,6 @@ module Sidekiq
5
5
  extend WebRouter
6
6
 
7
7
  CONTENT_LENGTH = "Content-Length"
8
- CONTENT_TYPE = "Content-Type"
9
8
  REDIS_KEYS = %w[redis_version uptime_in_days connected_clients used_memory_human used_memory_peak_human]
10
9
  CSP_HEADER = [
11
10
  "default-src 'self' https: http:",
@@ -84,7 +83,7 @@ module Sidekiq
84
83
 
85
84
  @count = (params["count"] || 25).to_i
86
85
  @queue = Sidekiq::Queue.new(@name)
87
- (@current_page, @total_size, @messages) = page("queue:#{@name}", params["page"], @count)
86
+ (@current_page, @total_size, @messages) = page("queue:#{@name}", params["page"], @count, reverse: params["direction"] == "asc")
88
87
  @messages = @messages.map { |msg| Sidekiq::Job.new(msg, @name) }
89
88
 
90
89
  erb(:queue)
@@ -283,17 +282,13 @@ module Sidekiq
283
282
  action = self.class.match(env)
284
283
  return [404, {"Content-Type" => "text/plain", "X-Cascade" => "pass"}, ["Not Found"]] unless action
285
284
 
286
- resp = catch(:halt) {
287
- app = @klass
285
+ app = @klass
286
+ resp = catch(:halt) do # rubocop:disable Standard/SemanticBlocks
288
287
  self.class.run_befores(app, action)
289
- begin
290
- resp = action.instance_exec env, &action.block
291
- ensure
292
- self.class.run_afters(app, action)
293
- end
294
-
295
- resp
296
- }
288
+ action.instance_exec env, &action.block
289
+ ensure
290
+ self.class.run_afters(app, action)
291
+ end
297
292
 
298
293
  resp = case resp
299
294
  when Array
@@ -311,7 +306,7 @@ module Sidekiq
311
306
 
312
307
  resp[1] = resp[1].dup
313
308
 
314
- resp[1][CONTENT_LENGTH] = resp[2].inject(0) { |l, p| l + p.bytesize }.to_s
309
+ resp[1][CONTENT_LENGTH] = resp[2].sum(&:bytesize).to_s
315
310
 
316
311
  resp
317
312
  end
@@ -65,7 +65,10 @@ module Sidekiq
65
65
 
66
66
  def poll_path
67
67
  if current_path != "" && params["poll"]
68
- root_path + current_path
68
+ path = root_path + current_path
69
+ query_string = to_query_string(params.slice(*params.keys - %w[page poll]))
70
+ path += "?#{query_string}" unless query_string.empty?
71
+ path
69
72
  else
70
73
  ""
71
74
  end
@@ -112,6 +115,13 @@ module Sidekiq
112
115
  end
113
116
  end
114
117
 
118
+ # within is used by Sidekiq Pro
119
+ def display_tags(job, within = nil)
120
+ job.tags.map { |tag|
121
+ "<span class='jobtag label label-info'>#{::Rack::Utils.escape_html(tag)}</span>"
122
+ }.join(" ")
123
+ end
124
+
115
125
  # mperham/sidekiq#3243
116
126
  def unfiltered?
117
127
  yield unless env["PATH_INFO"].start_with?("/filter/")
@@ -130,6 +140,10 @@ module Sidekiq
130
140
  end
131
141
  end
132
142
 
143
+ def sort_direction_label
144
+ params[:direction] == "asc" ? "&uarr;" : "&darr;"
145
+ end
146
+
133
147
  def workers
134
148
  @workers ||= Sidekiq::Workers.new
135
149
  end
@@ -142,12 +156,6 @@ module Sidekiq
142
156
  @stats ||= Sidekiq::Stats.new
143
157
  end
144
158
 
145
- def retries_with_score(score)
146
- Sidekiq.redis { |conn|
147
- conn.zrangebyscore("retry", score, score)
148
- }.map { |msg| Sidekiq.load_json(msg) }
149
- end
150
-
151
159
  def redis_connection
152
160
  Sidekiq.redis do |conn|
153
161
  c = conn.connection
@@ -189,7 +197,7 @@ module Sidekiq
189
197
  [score.to_f, jid]
190
198
  end
191
199
 
192
- SAFE_QPARAMS = %w[page poll]
200
+ SAFE_QPARAMS = %w[page poll direction]
193
201
 
194
202
  # Merge options with current params, filter safe params, and stringify to query string
195
203
  def qparams(options)
@@ -198,7 +206,11 @@ module Sidekiq
198
206
  options[key.to_s] = options.delete(key)
199
207
  end
200
208
 
201
- params.merge(options).map { |key, value|
209
+ to_query_string(params.merge(options))
210
+ end
211
+
212
+ def to_query_string(params)
213
+ params.map { |key, value|
202
214
  SAFE_QPARAMS.include?(key) ? "#{key}=#{CGI.escape(value.to_s)}" : next
203
215
  }.compact.join("&")
204
216
  end
@@ -238,7 +250,7 @@ module Sidekiq
238
250
  queue class args retry_count retried_at failed_at
239
251
  jid error_message error_class backtrace
240
252
  error_backtrace enqueued_at retry wrapped
241
- created_at
253
+ created_at tags
242
254
  ])
243
255
 
244
256
  def retry_extra_items(retry_job)
@@ -171,9 +171,9 @@ module Sidekiq
171
171
  now = Time.now.to_f
172
172
  ts = (int < 1_000_000_000 ? now + int : int)
173
173
 
174
- payload = @opts.merge("class" => @klass, "args" => args, "at" => ts)
174
+ payload = @opts.merge("class" => @klass, "args" => args)
175
175
  # Optimization to enqueue something now that is scheduled to go out now or in the past
176
- payload.delete("at") if ts <= now
176
+ payload["at"] = ts if ts > now
177
177
  @klass.client_push(payload)
178
178
  end
179
179
  alias_method :perform_at, :perform_in
@@ -207,10 +207,10 @@ module Sidekiq
207
207
  now = Time.now.to_f
208
208
  ts = (int < 1_000_000_000 ? now + int : int)
209
209
 
210
- item = {"class" => self, "args" => args, "at" => ts}
210
+ item = {"class" => self, "args" => args}
211
211
 
212
212
  # Optimization to enqueue something now that is scheduled to go out now or in the past
213
- item.delete("at") if ts <= now
213
+ item["at"] = ts if ts > now
214
214
 
215
215
  client_push(item)
216
216
  end
data/lib/sidekiq.rb CHANGED
@@ -192,6 +192,7 @@ module Sidekiq
192
192
 
193
193
  def self.log_formatter=(log_formatter)
194
194
  @log_formatter = log_formatter
195
+ logger.formatter = log_formatter
195
196
  end
196
197
 
197
198
  def self.logger
@@ -199,6 +200,13 @@ module Sidekiq
199
200
  end
200
201
 
201
202
  def self.logger=(logger)
203
+ if logger.nil?
204
+ self.logger.level = Logger::FATAL
205
+ return self.logger
206
+ end
207
+
208
+ logger.extend(Sidekiq::LoggingUtils)
209
+
202
210
  @logger = logger
203
211
  end
204
212
 
data/sidekiq.gemspec CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |gem|
8
8
  gem.homepage = "http://sidekiq.org"
9
9
  gem.license = "LGPL-3.0"
10
10
 
11
- gem.executables = ["sidekiq"]
11
+ gem.executables = ["sidekiq", "sidekiqmon"]
12
12
  gem.files = `git ls-files | grep -Ev '^(test|myapp|examples)'`.split("\n")
13
13
  gem.name = "sidekiq"
14
14
  gem.version = Sidekiq::VERSION
@@ -27,7 +27,7 @@ var realtimeGraph = function(updatePath) {
27
27
  renderer: 'line',
28
28
  interpolation: 'linear',
29
29
 
30
- series: new Rickshaw.Series.FixedDuration([{ name: graphElement.dataset.failedLabel, color: '#B1003E' }, { name: graphElement.dataset.processedLabel, color: '#006f68' }], undefined, {
30
+ series: new Rickshaw.Series.FixedDuration([{ name: graphElement.dataset.failedLabel, color: '#af0014' }, { name: graphElement.dataset.processedLabel, color: '#006f68' }], undefined, {
31
31
  timeInterval: timeInterval,
32
32
  maxDataPoints: 100,
33
33
  })
@@ -125,7 +125,7 @@ var historyGraph = function() {
125
125
  interpolation: 'linear',
126
126
  series: [
127
127
  {
128
- color: "#B1003E",
128
+ color: "#af0014",
129
129
  data: failed,
130
130
  name: graphElement.dataset.failedLabel
131
131
  }, {
@@ -0,0 +1,125 @@
1
+ @media (prefers-color-scheme: dark) {
2
+
3
+ body {
4
+ background-color: #000;
5
+ color: #ccc;
6
+ }
7
+
8
+ a,
9
+ .title,
10
+ .summary_bar ul .count,
11
+ .navbar .navbar-brand {
12
+ color: #af0014;
13
+ }
14
+
15
+ .navbar .navbar-brand:hover {
16
+ color: #ccc;
17
+ }
18
+
19
+ .navbar .navbar-brand .status {
20
+ color: #ccc;
21
+ }
22
+
23
+ .navbar-inverse {
24
+ background-color: #000;
25
+ border-color: #333;
26
+ }
27
+
28
+ table.table-white {
29
+ background-color: #111;
30
+ }
31
+
32
+ .table-striped > tbody > tr:nth-of-type(odd) {
33
+ background-color: #222;
34
+ }
35
+
36
+ .table-bordered,
37
+ .table-bordered > tbody > tr > td,
38
+ .table-bordered > tbody > tr > th,
39
+ .table-bordered > tfoot > tr > td,
40
+ .table-bordered > tfoot > tr > th,
41
+ .table-bordered > thead > tr > td,
42
+ .table-bordered > thead > tr > th {
43
+ border: 1px solid #333;
44
+ }
45
+
46
+ .table-hover > tbody > tr:hover {
47
+ background-color: #333;
48
+ }
49
+
50
+ .alert {
51
+ border: none;
52
+ color: #ccc;
53
+ }
54
+
55
+ .alert-success {
56
+ background-color: #000;
57
+ }
58
+
59
+ a:link,
60
+ a:active,
61
+ a:hover,
62
+ a:visited {
63
+ color: #63798c;
64
+ }
65
+
66
+ a.btn {
67
+ color: #000;
68
+ }
69
+
70
+ .summary_bar .summary {
71
+ background-color: #000;
72
+ border: 1px solid #333;
73
+ }
74
+
75
+ .navbar-default {
76
+ background-color: #000;
77
+ border-color: #3d3d3d;
78
+ }
79
+
80
+ .navbar-default .navbar-nav > .active > a,
81
+ .navbar-default .navbar-nav > .active > a:focus,
82
+ .navbar-default .navbar-nav > .active > a:hover {
83
+ color: #ccc;
84
+ background-color: #282828;
85
+ }
86
+
87
+ .navbar-default .navbar-nav > li > a:hover {
88
+ color: #ccc;
89
+ }
90
+
91
+ .pagination > li > a,
92
+ .pagination > li > a:hover,
93
+ .pagination > li > span {
94
+ color: #ccc;
95
+ background-color: #282828;
96
+ border-color: #353535;
97
+ }
98
+ .pagination > .disabled > a,
99
+ .pagination > .disabled > a:focus,
100
+ .pagination > .disabled > a:hover,
101
+ .pagination > .disabled > span,
102
+ .pagination > .disabled > span:focus,
103
+ .pagination > .disabled > span:hover {
104
+ color: #a5a5a5;
105
+ background-color: #282828;
106
+ border-color: #353535;
107
+ }
108
+
109
+ .stat {
110
+ border: 1px solid rgba(255, 255, 255, 0.1);
111
+ }
112
+
113
+ #live-poll {
114
+ color: #ccc;
115
+ }
116
+
117
+ .btn-warn {
118
+ color: #333;
119
+ }
120
+
121
+ .rickshaw_graph .y_ticks.glow text {
122
+ fill: #ccc;
123
+ color: #ccc;
124
+ }
125
+ }
@@ -201,6 +201,15 @@ td form {
201
201
  padding: 0;
202
202
  }
203
203
 
204
+ .jobtag a {
205
+ color: white;
206
+ }
207
+
208
+ .jobtag a:hover {
209
+ color: white;
210
+ text-decoration: underline;
211
+ }
212
+
204
213
  table .table-checkbox label {
205
214
  height: 100%;
206
215
  width: 100%;
data/web/locales/de.yml CHANGED
@@ -13,7 +13,7 @@ de:
13
13
  Retries: Versuche
14
14
  Enqueued: In der Warteschlange
15
15
  Worker: Arbeiter
16
- LivePoll: Live Poll
16
+ LivePoll: Echtzeitabfrage
17
17
  StopPolling: Abfrage stoppen
18
18
  Queue: Warteschlange
19
19
  Class: Klasse
@@ -33,12 +33,13 @@ de:
33
33
  NextRetry: Nächster Versuch
34
34
  RetryCount: Anzahl der Versuche
35
35
  RetryNow: Jetzt erneut versuchen
36
- Kill: Töten
36
+ Kill: Vernichten
37
37
  LastRetry: Letzter Versuch
38
38
  OriginallyFailed: Ursprünglich fehlgeschlagen
39
39
  AreYouSure: Bist du sicher?
40
40
  DeleteAll: Alle löschen
41
41
  RetryAll: Alle erneut versuchen
42
+ KillAll: Alle vernichten
42
43
  NoRetriesFound: Keine erneuten Versuche gefunden
43
44
  Error: Fehler
44
45
  ErrorClass: Fehlerklasse
@@ -67,3 +68,14 @@ de:
67
68
  Thread: Thread
68
69
  Threads: Threads
69
70
  Jobs: Jobs
71
+ Paused: Pausiert
72
+ Stop: Stopp
73
+ Quiet: Leise
74
+ StopAll: Alle stoppen
75
+ QuietAll: Alle leise
76
+ PollingInterval: Abfrageintervall
77
+ Plugins: Erweiterungen
78
+ NotYetEnqueued: Noch nicht in der Warteschlange
79
+ CreatedAt: Erstellt
80
+ BackToApp: Zurück zur Anwendung
81
+ Latency: Latenz
@@ -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/busy.erb CHANGED
@@ -87,7 +87,10 @@
87
87
  <td>
88
88
  <a href="<%= root_path %>queues/<%= msg['queue'] %>"><%= msg['queue'] %></a>
89
89
  </td>
90
- <td><%= job.display_class %></td>
90
+ <td>
91
+ <%= job.display_class %>
92
+ <%= display_tags(job, nil) %>
93
+ </td>
91
94
  <td>
92
95
  <div class="args"><%= display_args(job.display_args) %></div>
93
96
  </td>
data/web/views/dead.erb CHANGED
@@ -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,6 +11,7 @@
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" 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 %>
data/web/views/morgue.erb CHANGED
@@ -42,7 +42,10 @@
42
42
  <td>
43
43
  <a href="<%= root_path %>queues/<%= entry.queue %>"><%= entry.queue %></a>
44
44
  </td>
45
- <td><%= entry.display_class %></td>
45
+ <td>
46
+ <%= entry.display_class %>
47
+ <%= display_tags(entry, "morgue") %>
48
+ </td>
46
49
  <td>
47
50
  <div class="args"><%= display_args(entry.display_args) %></div>
48
51
  </td>
data/web/views/queue.erb CHANGED
@@ -15,13 +15,22 @@
15
15
  <div class="table_container">
16
16
  <table class="queue table table-hover table-bordered table-striped">
17
17
  <thead>
18
+ <th><a href="<%= url %>?direction=<%= params[:direction] == 'asc' ? 'desc' : 'asc' %>"># <%= sort_direction_label %></a></th>
18
19
  <th><%= t('Job') %></th>
19
20
  <th><%= t('Arguments') %></th>
20
21
  <th></th>
21
22
  </thead>
22
23
  <% @messages.each_with_index do |msg, index| %>
23
24
  <tr>
24
- <td><%= h(msg.display_class) %></td>
25
+ <% if params[:direction] == 'asc' %>
26
+ <td><%= @count * (@current_page - 1) + index + 1 %></td>
27
+ <% else %>
28
+ <td><%= @total_size - (@count * (@current_page - 1) + index) %></td>
29
+ <% end %>
30
+ <td>
31
+ <%= h(msg.display_class) %>
32
+ <%= display_tags(msg, nil) %>
33
+ </td>
25
34
  <td>
26
35
  <% a = msg.display_args %>
27
36
  <% if a.inspect.size > 100 %>
@@ -44,7 +44,10 @@
44
44
  <td>
45
45
  <a href="<%= root_path %>queues/<%= entry.queue %>"><%= entry.queue %></a>
46
46
  </td>
47
- <td><%= entry.display_class %></td>
47
+ <td>
48
+ <%= entry.display_class %>
49
+ <%= display_tags(entry, "retries") %>
50
+ </td>
48
51
  <td>
49
52
  <div class="args"><%= display_args(entry.display_args) %></div>
50
53
  </td>
data/web/views/retry.erb CHANGED
@@ -14,11 +14,11 @@
14
14
  <th><%= t('ErrorMessage') %></th>
15
15
  <td><%= h(@retry['error_message']) %></td>
16
16
  </tr>
17
- <% if !@retry['error_backtrace'].nil? %>
17
+ <% if @retry.error_backtrace %>
18
18
  <tr>
19
19
  <th><%= t('ErrorBacktrace') %></th>
20
20
  <td>
21
- <code><%= @retry['error_backtrace'].join("<br/>") %></code>
21
+ <code><%= @retry.error_backtrace.join("<br/>") %></code>
22
22
  </td>
23
23
  </tr>
24
24
  <% end %>
@@ -38,7 +38,10 @@
38
38
  <td>
39
39
  <a href="<%= root_path %>queues/<%= entry.queue %>"><%= entry.queue %></a>
40
40
  </td>
41
- <td><%= entry.display_class %></td>
41
+ <td>
42
+ <%= entry.display_class %>
43
+ <%= display_tags(entry, "scheduled") %>
44
+ </td>
42
45
  <td>
43
46
  <div class="args"><%= display_args(entry.display_args) %></div>
44
47
  </td>
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: 6.0.0
4
+ version: 6.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Perham
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-30 00:00:00.000000000 Z
11
+ date: 2019-10-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -71,6 +71,7 @@ email:
71
71
  - mperham@gmail.com
72
72
  executables:
73
73
  - sidekiq
74
+ - sidekiqmon
74
75
  extensions: []
75
76
  extra_rdoc_files: []
76
77
  files:
@@ -145,6 +146,7 @@ files:
145
146
  - web/assets/images/status.png
146
147
  - web/assets/javascripts/application.js
147
148
  - web/assets/javascripts/dashboard.js
149
+ - web/assets/stylesheets/application-dark.css
148
150
  - web/assets/stylesheets/application-rtl.css
149
151
  - web/assets/stylesheets/application.css
150
152
  - web/assets/stylesheets/bootstrap-rtl.min.css
@@ -212,8 +214,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
212
214
  - !ruby/object:Gem::Version
213
215
  version: '0'
214
216
  requirements: []
215
- rubyforge_project:
216
- rubygems_version: 2.7.6
217
+ rubygems_version: 3.0.3
217
218
  signing_key:
218
219
  specification_version: 4
219
220
  summary: Simple, efficient background processing for Ruby