sidekiq 5.2.4 → 6.0.1

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 (78) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +82 -0
  3. data/.gitignore +0 -2
  4. data/.standard.yml +20 -0
  5. data/6.0-Upgrade.md +72 -0
  6. data/COMM-LICENSE +11 -9
  7. data/Changes.md +129 -0
  8. data/Ent-2.0-Upgrade.md +37 -0
  9. data/Ent-Changes.md +32 -1
  10. data/Gemfile +12 -17
  11. data/Gemfile.lock +196 -0
  12. data/Pro-5.0-Upgrade.md +25 -0
  13. data/Pro-Changes.md +26 -2
  14. data/README.md +18 -31
  15. data/Rakefile +5 -4
  16. data/bin/sidekiqload +33 -25
  17. data/bin/sidekiqmon +8 -0
  18. data/lib/generators/sidekiq/templates/worker_test.rb.erb +1 -1
  19. data/lib/generators/sidekiq/worker_generator.rb +20 -12
  20. data/lib/sidekiq.rb +62 -43
  21. data/lib/sidekiq/api.rb +196 -175
  22. data/lib/sidekiq/cli.rb +118 -178
  23. data/lib/sidekiq/client.rb +51 -46
  24. data/lib/sidekiq/delay.rb +5 -6
  25. data/lib/sidekiq/exception_handler.rb +10 -12
  26. data/lib/sidekiq/extensions/action_mailer.rb +10 -20
  27. data/lib/sidekiq/extensions/active_record.rb +9 -7
  28. data/lib/sidekiq/extensions/class_methods.rb +9 -7
  29. data/lib/sidekiq/extensions/generic_proxy.rb +4 -4
  30. data/lib/sidekiq/fetch.rb +11 -12
  31. data/lib/sidekiq/job_logger.rb +45 -7
  32. data/lib/sidekiq/job_retry.rb +67 -58
  33. data/lib/sidekiq/launcher.rb +57 -51
  34. data/lib/sidekiq/logger.rb +165 -0
  35. data/lib/sidekiq/manager.rb +7 -9
  36. data/lib/sidekiq/middleware/chain.rb +14 -4
  37. data/lib/sidekiq/middleware/i18n.rb +5 -7
  38. data/lib/sidekiq/monitor.rb +148 -0
  39. data/lib/sidekiq/paginator.rb +18 -14
  40. data/lib/sidekiq/processor.rb +96 -66
  41. data/lib/sidekiq/rails.rb +23 -29
  42. data/lib/sidekiq/redis_connection.rb +31 -37
  43. data/lib/sidekiq/scheduled.rb +28 -29
  44. data/lib/sidekiq/testing.rb +34 -23
  45. data/lib/sidekiq/testing/inline.rb +2 -1
  46. data/lib/sidekiq/util.rb +17 -14
  47. data/lib/sidekiq/version.rb +2 -1
  48. data/lib/sidekiq/web.rb +41 -49
  49. data/lib/sidekiq/web/action.rb +14 -10
  50. data/lib/sidekiq/web/application.rb +63 -64
  51. data/lib/sidekiq/web/helpers.rb +92 -68
  52. data/lib/sidekiq/web/router.rb +17 -14
  53. data/lib/sidekiq/worker.rb +129 -97
  54. data/sidekiq.gemspec +16 -16
  55. data/web/assets/javascripts/dashboard.js +4 -23
  56. data/web/assets/stylesheets/application-dark.css +125 -0
  57. data/web/assets/stylesheets/application.css +9 -0
  58. data/web/assets/stylesheets/bootstrap.css +1 -1
  59. data/web/locales/ja.yml +2 -1
  60. data/web/views/_job_info.erb +2 -1
  61. data/web/views/busy.erb +4 -1
  62. data/web/views/dead.erb +2 -2
  63. data/web/views/layout.erb +1 -0
  64. data/web/views/morgue.erb +4 -1
  65. data/web/views/queue.erb +10 -1
  66. data/web/views/queues.erb +1 -1
  67. data/web/views/retries.erb +4 -1
  68. data/web/views/retry.erb +2 -2
  69. data/web/views/scheduled.erb +4 -1
  70. metadata +20 -30
  71. data/.travis.yml +0 -17
  72. data/Appraisals +0 -9
  73. data/bin/sidekiqctl +0 -237
  74. data/gemfiles/rails_4.gemfile +0 -31
  75. data/gemfiles/rails_5.gemfile +0 -31
  76. data/lib/sidekiq/core_ext.rb +0 -1
  77. data/lib/sidekiq/logging.rb +0 -122
  78. data/lib/sidekiq/middleware/server/active_record.rb +0 -23
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Sidekiq
4
4
  class WebAction
5
- RACK_SESSION = 'rack.session'
5
+ RACK_SESSION = "rack.session"
6
6
 
7
7
  attr_accessor :env, :block, :type
8
8
 
@@ -19,14 +19,14 @@ module Sidekiq
19
19
  end
20
20
 
21
21
  def redirect(location)
22
- throw :halt, [302, { "Location" => "#{request.base_url}#{location}" }, []]
22
+ throw :halt, [302, {"Location" => "#{request.base_url}#{location}"}, []]
23
23
  end
24
24
 
25
25
  def params
26
- indifferent_hash = Hash.new {|hash,key| hash[key.to_s] if Symbol === key }
26
+ indifferent_hash = Hash.new { |hash, key| hash[key.to_s] if Symbol === key }
27
27
 
28
28
  indifferent_hash.merge! request.params
29
- route_params.each {|k,v| indifferent_hash[k.to_s] = v }
29
+ route_params.each { |k, v| indifferent_hash[k.to_s] = v }
30
30
 
31
31
  indifferent_hash
32
32
  end
@@ -40,10 +40,14 @@ module Sidekiq
40
40
  end
41
41
 
42
42
  def erb(content, options = {})
43
- if content.kind_of? Symbol
43
+ if content.is_a? Symbol
44
44
  unless respond_to?(:"_erb_#{content}")
45
45
  src = ERB.new(File.read("#{Web.settings.views}/#{content}.erb")).src
46
- WebAction.class_eval("def _erb_#{content}\n#{src}\n end")
46
+ WebAction.class_eval <<-RUBY, __FILE__, __LINE__ + 1
47
+ def _erb_#{content}
48
+ #{src}
49
+ end
50
+ RUBY
47
51
  end
48
52
  end
49
53
 
@@ -64,22 +68,22 @@ module Sidekiq
64
68
  end
65
69
 
66
70
  def json(payload)
67
- [200, { "Content-Type" => "application/json", "Cache-Control" => "no-cache" }, [Sidekiq.dump_json(payload)]]
71
+ [200, {"Content-Type" => "application/json", "Cache-Control" => "no-cache"}, [Sidekiq.dump_json(payload)]]
68
72
  end
69
73
 
70
74
  def initialize(env, block)
71
75
  @_erb = false
72
76
  @env = env
73
77
  @block = block
74
- @@files ||= {}
78
+ @files ||= {}
75
79
  end
76
80
 
77
81
  private
78
82
 
79
83
  def _erb(file, locals)
80
- locals.each {|k, v| define_singleton_method(k){ v } unless (singleton_methods.include? k)} if locals
84
+ locals&.each { |k, v| define_singleton_method(k) { v } unless singleton_methods.include? k }
81
85
 
82
- if file.kind_of?(String)
86
+ if file.is_a?(String)
83
87
  ERB.new(file).result(binding)
84
88
  else
85
89
  send(:"_erb_#{file}")
@@ -6,7 +6,7 @@ module Sidekiq
6
6
 
7
7
  CONTENT_LENGTH = "Content-Length"
8
8
  CONTENT_TYPE = "Content-Type"
9
- REDIS_KEYS = %w(redis_version uptime_in_days connected_clients used_memory_human used_memory_peak_human)
9
+ REDIS_KEYS = %w[redis_version uptime_in_days connected_clients used_memory_human used_memory_peak_human]
10
10
  CSP_HEADER = [
11
11
  "default-src 'self' https: http:",
12
12
  "child-src 'self'",
@@ -20,8 +20,8 @@ module Sidekiq
20
20
  "script-src 'self' https: http: 'unsafe-inline'",
21
21
  "style-src 'self' https: http: 'unsafe-inline'",
22
22
  "worker-src 'self'",
23
- "base-uri 'self'"
24
- ].join('; ').freeze
23
+ "base-uri 'self'",
24
+ ].join("; ").freeze
25
25
 
26
26
  def initialize(klass)
27
27
  @klass = klass
@@ -44,8 +44,8 @@ module Sidekiq
44
44
  end
45
45
 
46
46
  get "/" do
47
- @redis_info = redis_info.select{ |k, v| REDIS_KEYS.include? k }
48
- stats_history = Sidekiq::Stats::History.new((params['days'] || 30).to_i)
47
+ @redis_info = redis_info.select { |k, v| REDIS_KEYS.include? k }
48
+ stats_history = Sidekiq::Stats::History.new((params["days"] || 30).to_i)
49
49
  @processed_history = stats_history.processed
50
50
  @failed_history = stats_history.failed
51
51
 
@@ -57,14 +57,14 @@ module Sidekiq
57
57
  end
58
58
 
59
59
  post "/busy" do
60
- if params['identity']
61
- p = Sidekiq::Process.new('identity' => params['identity'])
62
- p.quiet! if params['quiet']
63
- p.stop! if params['stop']
60
+ if params["identity"]
61
+ p = Sidekiq::Process.new("identity" => params["identity"])
62
+ p.quiet! if params["quiet"]
63
+ p.stop! if params["stop"]
64
64
  else
65
65
  processes.each do |pro|
66
- pro.quiet! if params['quiet']
67
- pro.stop! if params['stop']
66
+ pro.quiet! if params["quiet"]
67
+ pro.stop! if params["stop"]
68
68
  end
69
69
  end
70
70
 
@@ -82,9 +82,9 @@ module Sidekiq
82
82
 
83
83
  halt(404) unless @name
84
84
 
85
- @count = (params['count'] || 25).to_i
85
+ @count = (params["count"] || 25).to_i
86
86
  @queue = Sidekiq::Queue.new(@name)
87
- (@current_page, @total_size, @messages) = page("queue:#{@name}", params['page'], @count)
87
+ (@current_page, @total_size, @messages) = page("queue:#{@name}", params["page"], @count, reverse: params["direction"] == "asc")
88
88
  @messages = @messages.map { |msg| Sidekiq::Job.new(msg, @name) }
89
89
 
90
90
  erb(:queue)
@@ -98,21 +98,22 @@ module Sidekiq
98
98
 
99
99
  post "/queues/:name/delete" do
100
100
  name = route_params[:name]
101
- Sidekiq::Job.new(params['key_val'], name).delete
101
+ Sidekiq::Job.new(params["key_val"], name).delete
102
102
 
103
103
  redirect_with_query("#{root_path}queues/#{CGI.escape(name)}")
104
104
  end
105
105
 
106
- get '/morgue' do
107
- @count = (params['count'] || 25).to_i
108
- (@current_page, @total_size, @dead) = page("dead", params['page'], @count, reverse: true)
106
+ get "/morgue" do
107
+ @count = (params["count"] || 25).to_i
108
+ (@current_page, @total_size, @dead) = page("dead", params["page"], @count, reverse: true)
109
109
  @dead = @dead.map { |msg, score| Sidekiq::SortedEntry.new(nil, score, msg) }
110
110
 
111
111
  erb(:morgue)
112
112
  end
113
113
 
114
114
  get "/morgue/:key" do
115
- halt(404) unless key = route_params[:key]
115
+ key = route_params[:key]
116
+ halt(404) unless key
116
117
 
117
118
  @dead = Sidekiq::DeadSet.new.fetch(*parse_params(key)).first
118
119
 
@@ -123,10 +124,10 @@ module Sidekiq
123
124
  end
124
125
  end
125
126
 
126
- post '/morgue' do
127
- redirect(request.path) unless params['key']
127
+ post "/morgue" do
128
+ redirect(request.path) unless params["key"]
128
129
 
129
- params['key'].each do |key|
130
+ params["key"].each do |key|
130
131
  job = Sidekiq::DeadSet.new.fetch(*parse_params(key)).first
131
132
  retry_or_delete_or_kill job, params if job
132
133
  end
@@ -147,7 +148,8 @@ module Sidekiq
147
148
  end
148
149
 
149
150
  post "/morgue/:key" do
150
- halt(404) unless key = route_params[:key]
151
+ key = route_params[:key]
152
+ halt(404) unless key
151
153
 
152
154
  job = Sidekiq::DeadSet.new.fetch(*parse_params(key)).first
153
155
  retry_or_delete_or_kill job, params if job
@@ -155,9 +157,9 @@ module Sidekiq
155
157
  redirect_with_query("#{root_path}morgue")
156
158
  end
157
159
 
158
- get '/retries' do
159
- @count = (params['count'] || 25).to_i
160
- (@current_page, @total_size, @retries) = page("retry", params['page'], @count)
160
+ get "/retries" do
161
+ @count = (params["count"] || 25).to_i
162
+ (@current_page, @total_size, @retries) = page("retry", params["page"], @count)
161
163
  @retries = @retries.map { |msg, score| Sidekiq::SortedEntry.new(nil, score, msg) }
162
164
 
163
165
  erb(:retries)
@@ -173,10 +175,10 @@ module Sidekiq
173
175
  end
174
176
  end
175
177
 
176
- post '/retries' do
177
- redirect(request.path) unless params['key']
178
+ post "/retries" do
179
+ redirect(request.path) unless params["key"]
178
180
 
179
- params['key'].each do |key|
181
+ params["key"].each do |key|
180
182
  job = Sidekiq::RetrySet.new.fetch(*parse_params(key)).first
181
183
  retry_or_delete_or_kill job, params if job
182
184
  end
@@ -210,9 +212,9 @@ module Sidekiq
210
212
  redirect_with_query("#{root_path}retries")
211
213
  end
212
214
 
213
- get '/scheduled' do
214
- @count = (params['count'] || 25).to_i
215
- (@current_page, @total_size, @scheduled) = page("schedule", params['page'], @count)
215
+ get "/scheduled" do
216
+ @count = (params["count"] || 25).to_i
217
+ (@current_page, @total_size, @scheduled) = page("schedule", params["page"], @count)
216
218
  @scheduled = @scheduled.map { |msg, score| Sidekiq::SortedEntry.new(nil, score, msg) }
217
219
 
218
220
  erb(:scheduled)
@@ -228,10 +230,10 @@ module Sidekiq
228
230
  end
229
231
  end
230
232
 
231
- post '/scheduled' do
232
- redirect(request.path) unless params['key']
233
+ post "/scheduled" do
234
+ redirect(request.path) unless params["key"]
233
235
 
234
- params['key'].each do |key|
236
+ params["key"].each do |key|
235
237
  job = Sidekiq::ScheduledSet.new.fetch(*parse_params(key)).first
236
238
  delete_or_add_queue job, params if job
237
239
  end
@@ -240,7 +242,8 @@ module Sidekiq
240
242
  end
241
243
 
242
244
  post "/scheduled/:key" do
243
- halt(404) unless key = route_params[:key]
245
+ key = route_params[:key]
246
+ halt(404) unless key
244
247
 
245
248
  job = Sidekiq::ScheduledSet.new.fetch(*parse_params(key)).first
246
249
  delete_or_add_queue job, params if job
@@ -248,48 +251,44 @@ module Sidekiq
248
251
  redirect_with_query("#{root_path}scheduled")
249
252
  end
250
253
 
251
- get '/dashboard/stats' do
254
+ get "/dashboard/stats" do
252
255
  redirect "#{root_path}stats"
253
256
  end
254
257
 
255
- get '/stats' do
258
+ get "/stats" do
256
259
  sidekiq_stats = Sidekiq::Stats.new
257
- redis_stats = redis_info.select { |k, v| REDIS_KEYS.include? k }
260
+ redis_stats = redis_info.select { |k, v| REDIS_KEYS.include? k }
258
261
  json(
259
262
  sidekiq: {
260
- processed: sidekiq_stats.processed,
261
- failed: sidekiq_stats.failed,
262
- busy: sidekiq_stats.workers_size,
263
- processes: sidekiq_stats.processes_size,
264
- enqueued: sidekiq_stats.enqueued,
265
- scheduled: sidekiq_stats.scheduled_size,
266
- retries: sidekiq_stats.retry_size,
267
- dead: sidekiq_stats.dead_size,
268
- default_latency: sidekiq_stats.default_queue_latency
263
+ processed: sidekiq_stats.processed,
264
+ failed: sidekiq_stats.failed,
265
+ busy: sidekiq_stats.workers_size,
266
+ processes: sidekiq_stats.processes_size,
267
+ enqueued: sidekiq_stats.enqueued,
268
+ scheduled: sidekiq_stats.scheduled_size,
269
+ retries: sidekiq_stats.retry_size,
270
+ dead: sidekiq_stats.dead_size,
271
+ default_latency: sidekiq_stats.default_queue_latency,
269
272
  },
270
273
  redis: redis_stats,
271
274
  server_utc_time: server_utc_time
272
275
  )
273
276
  end
274
277
 
275
- get '/stats/queues' do
278
+ get "/stats/queues" do
276
279
  json Sidekiq::Stats::Queues.new.lengths
277
280
  end
278
281
 
279
282
  def call(env)
280
283
  action = self.class.match(env)
281
- return [404, {"Content-Type" => "text/plain", "X-Cascade" => "pass" }, ["Not Found"]] unless action
284
+ return [404, {"Content-Type" => "text/plain", "X-Cascade" => "pass"}, ["Not Found"]] unless action
282
285
 
283
- resp = catch(:halt) do
284
- app = @klass
286
+ app = @klass
287
+ resp = catch(:halt) do # rubocop:disable Standard/SemanticBlocks
285
288
  self.class.run_befores(app, action)
286
- begin
287
- resp = action.instance_exec env, &action.block
288
- ensure
289
- self.class.run_afters(app, action)
290
- end
291
-
292
- resp
289
+ action.instance_exec env, &action.block
290
+ ensure
291
+ self.class.run_afters(app, action)
293
292
  end
294
293
 
295
294
  resp = case resp
@@ -300,7 +299,7 @@ module Sidekiq
300
299
  "Content-Type" => "text/html",
301
300
  "Cache-Control" => "no-cache",
302
301
  "Content-Language" => action.locale,
303
- "Content-Security-Policy" => CSP_HEADER
302
+ "Content-Security-Policy" => CSP_HEADER,
304
303
  }
305
304
 
306
305
  [200, headers, [resp]]
@@ -313,7 +312,7 @@ module Sidekiq
313
312
  resp
314
313
  end
315
314
 
316
- def self.helpers(mod=nil, &block)
315
+ def self.helpers(mod = nil, &block)
317
316
  if block_given?
318
317
  WebAction.class_eval(&block)
319
318
  else
@@ -321,11 +320,11 @@ module Sidekiq
321
320
  end
322
321
  end
323
322
 
324
- def self.before(path=nil, &block)
323
+ def self.before(path = nil, &block)
325
324
  befores << [path && Regexp.new("\\A#{path.gsub("*", ".*")}\\z"), block]
326
325
  end
327
326
 
328
- def self.after(path=nil, &block)
327
+ def self.after(path = nil, &block)
329
328
  afters << [path && Regexp.new("\\A#{path.gsub("*", ".*")}\\z"), block]
330
329
  end
331
330
 
@@ -338,8 +337,8 @@ module Sidekiq
338
337
  end
339
338
 
340
339
  def self.run_hooks(hooks, app, action)
341
- hooks.select { |p,_| !p || p =~ action.env[WebRouter::PATH_INFO] }.
342
- each {|_,b| action.instance_exec(action.env, app, &b) }
340
+ hooks.select { |p, _| !p || p =~ action.env[WebRouter::PATH_INFO] }
341
+ .each { |_, b| action.instance_exec(action.env, app, &b) }
343
342
  end
344
343
 
345
344
  def self.befores
@@ -1,15 +1,16 @@
1
1
  # frozen_string_literal: true
2
- require 'uri'
3
- require 'set'
4
- require 'yaml'
5
- require 'cgi'
2
+
3
+ require "uri"
4
+ require "set"
5
+ require "yaml"
6
+ require "cgi"
6
7
 
7
8
  module Sidekiq
8
9
  # This is not a public API
9
10
  module WebHelpers
10
11
  def strings(lang)
11
- @@strings ||= {}
12
- @@strings[lang] ||= begin
12
+ @strings ||= {}
13
+ @strings[lang] ||= begin
13
14
  # Allow sidekiq-web extensions to add locale paths
14
15
  # so extensions can be localized
15
16
  settings.locales.each_with_object({}) do |path, global|
@@ -22,19 +23,19 @@ module Sidekiq
22
23
  end
23
24
 
24
25
  def clear_caches
25
- @@strings = nil
26
- @@locale_files = nil
27
- @@available_locales = nil
26
+ @strings = nil
27
+ @locale_files = nil
28
+ @available_locales = nil
28
29
  end
29
30
 
30
31
  def locale_files
31
- @@locale_files ||= settings.locales.flat_map do |path|
32
+ @locale_files ||= settings.locales.flat_map { |path|
32
33
  Dir["#{path}/*.yml"]
33
- end
34
+ }
34
35
  end
35
36
 
36
37
  def available_locales
37
- @@available_locales ||= locale_files.map { |path| File.basename(path, '.yml') }.uniq
38
+ @available_locales ||= locale_files.map { |path| File.basename(path, ".yml") }.uniq
38
39
  end
39
40
 
40
41
  def find_locale_files(lang)
@@ -63,32 +64,35 @@ module Sidekiq
63
64
  end
64
65
 
65
66
  def poll_path
66
- if current_path != '' && params['poll']
67
- root_path + current_path
67
+ if current_path != "" && params["poll"]
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
68
72
  else
69
73
  ""
70
74
  end
71
75
  end
72
76
 
73
77
  def text_direction
74
- get_locale['TextDirection'] || 'ltr'
78
+ get_locale["TextDirection"] || "ltr"
75
79
  end
76
80
 
77
81
  def rtl?
78
- text_direction == 'rtl'
82
+ text_direction == "rtl"
79
83
  end
80
84
 
81
85
  # See https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
82
86
  def user_preferred_languages
83
- languages = env['HTTP_ACCEPT_LANGUAGE']
84
- languages.to_s.downcase.gsub(/\s+/, '').split(',').map do |language|
85
- locale, quality = language.split(';q=', 2)
86
- locale = nil if locale == '*' # Ignore wildcards
87
+ languages = env["HTTP_ACCEPT_LANGUAGE"]
88
+ languages.to_s.downcase.gsub(/\s+/, "").split(",").map { |language|
89
+ locale, quality = language.split(";q=", 2)
90
+ locale = nil if locale == "*" # Ignore wildcards
87
91
  quality = quality ? quality.to_f : 1.0
88
92
  [locale, quality]
89
- end.sort do |(_, left), (_, right)|
93
+ }.sort { |(_, left), (_, right)|
90
94
  right <=> left
91
- end.map(&:first).compact
95
+ }.map(&:first).compact
92
96
  end
93
97
 
94
98
  # Given an Accept-Language header like "fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4,ru;q=0.2"
@@ -97,31 +101,38 @@ module Sidekiq
97
101
  # Inspiration taken from https://github.com/iain/http_accept_language/blob/master/lib/http_accept_language/parser.rb
98
102
  def locale
99
103
  @locale ||= begin
100
- matched_locale = user_preferred_languages.map do |preferred|
101
- preferred_language = preferred.split('-', 2).first
104
+ matched_locale = user_preferred_languages.map { |preferred|
105
+ preferred_language = preferred.split("-", 2).first
102
106
 
103
- lang_group = available_locales.select do |available|
104
- preferred_language == available.split('-', 2).first
105
- end
107
+ lang_group = available_locales.select { |available|
108
+ preferred_language == available.split("-", 2).first
109
+ }
106
110
 
107
111
  lang_group.find { |lang| lang == preferred } || lang_group.min_by(&:length)
108
- end.compact.first
112
+ }.compact.first
109
113
 
110
- matched_locale || 'en'
114
+ matched_locale || "en"
111
115
  end
112
116
  end
113
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
+
114
125
  # mperham/sidekiq#3243
115
126
  def unfiltered?
116
- yield unless env['PATH_INFO'].start_with?("/filter/")
127
+ yield unless env["PATH_INFO"].start_with?("/filter/")
117
128
  end
118
129
 
119
130
  def get_locale
120
131
  strings(locale)
121
132
  end
122
133
 
123
- def t(msg, options={})
124
- string = get_locale[msg] || strings('en')[msg] || msg
134
+ def t(msg, options = {})
135
+ string = get_locale[msg] || strings("en")[msg] || msg
125
136
  if options.empty?
126
137
  string
127
138
  else
@@ -129,6 +140,10 @@ module Sidekiq
129
140
  end
130
141
  end
131
142
 
143
+ def sort_direction_label
144
+ params[:direction] == "asc" ? "&uarr;" : "&darr;"
145
+ end
146
+
132
147
  def workers
133
148
  @workers ||= Sidekiq::Workers.new
134
149
  end
@@ -142,9 +157,9 @@ module Sidekiq
142
157
  end
143
158
 
144
159
  def retries_with_score(score)
145
- Sidekiq.redis do |conn|
146
- conn.zrangebyscore('retry', score, score)
147
- end.map { |msg| Sidekiq.load_json(msg) }
160
+ Sidekiq.redis { |conn|
161
+ conn.zrangebyscore("retry", score, score)
162
+ }.map { |msg| Sidekiq.load_json(msg) }
148
163
  end
149
164
 
150
165
  def redis_connection
@@ -163,24 +178,24 @@ module Sidekiq
163
178
  end
164
179
 
165
180
  def root_path
166
- "#{env['SCRIPT_NAME']}/"
181
+ "#{env["SCRIPT_NAME"]}/"
167
182
  end
168
183
 
169
184
  def current_path
170
- @current_path ||= request.path_info.gsub(/^\//,'')
185
+ @current_path ||= request.path_info.gsub(/^\//, "")
171
186
  end
172
187
 
173
188
  def current_status
174
- workers.size == 0 ? 'idle' : 'active'
189
+ workers.size == 0 ? "idle" : "active"
175
190
  end
176
191
 
177
192
  def relative_time(time)
178
193
  stamp = time.getutc.iso8601
179
- %{<time class="ltr" dir="ltr" title="#{stamp}" datetime="#{stamp}">#{time}</time>}
194
+ %(<time class="ltr" dir="ltr" title="#{stamp}" datetime="#{stamp}">#{time}</time>)
180
195
  end
181
196
 
182
197
  def job_params(job, score)
183
- "#{score}-#{job['jid']}"
198
+ "#{score}-#{job["jid"]}"
184
199
  end
185
200
 
186
201
  def parse_params(params)
@@ -188,7 +203,7 @@ module Sidekiq
188
203
  [score.to_f, jid]
189
204
  end
190
205
 
191
- SAFE_QPARAMS = %w(page poll)
206
+ SAFE_QPARAMS = %w[page poll direction]
192
207
 
193
208
  # Merge options with current params, filter safe params, and stringify to query string
194
209
  def qparams(options)
@@ -197,9 +212,13 @@ module Sidekiq
197
212
  options[key.to_s] = options.delete(key)
198
213
  end
199
214
 
200
- params.merge(options).map do |key, value|
215
+ to_query_string(params.merge(options))
216
+ end
217
+
218
+ def to_query_string(params)
219
+ params.map { |key, value|
201
220
  SAFE_QPARAMS.include?(key) ? "#{key}=#{CGI.escape(value.to_s)}" : next
202
- end.compact.join("&")
221
+ }.compact.join("&")
203
222
  end
204
223
 
205
224
  def truncate(text, truncate_after_chars = 2000)
@@ -207,9 +226,16 @@ module Sidekiq
207
226
  end
208
227
 
209
228
  def display_args(args, truncate_after_chars = 2000)
210
- args.map do |arg|
211
- h(truncate(to_display(arg), truncate_after_chars))
212
- end.join(", ")
229
+ return "Invalid job payload, args is nil" if args.nil?
230
+ return "Invalid job payload, args must be an Array, not #{args.class.name}" unless args.is_a?(Array)
231
+
232
+ begin
233
+ args.map { |arg|
234
+ h(truncate(to_display(arg), truncate_after_chars))
235
+ }.join(", ")
236
+ rescue
237
+ "Illegal job arguments: #{h args.inspect}"
238
+ end
213
239
  end
214
240
 
215
241
  def csrf_tag
@@ -217,23 +243,21 @@ module Sidekiq
217
243
  end
218
244
 
219
245
  def to_display(arg)
246
+ arg.inspect
247
+ rescue
220
248
  begin
221
- arg.inspect
222
- rescue
223
- begin
224
- arg.to_s
225
- rescue => ex
226
- "Cannot display argument: [#{ex.class.name}] #{ex.message}"
227
- end
249
+ arg.to_s
250
+ rescue => ex
251
+ "Cannot display argument: [#{ex.class.name}] #{ex.message}"
228
252
  end
229
253
  end
230
254
 
231
- RETRY_JOB_KEYS = Set.new(%w(
255
+ RETRY_JOB_KEYS = Set.new(%w[
232
256
  queue class args retry_count retried_at failed_at
233
257
  jid error_message error_class backtrace
234
258
  error_backtrace enqueued_at retry wrapped
235
- created_at
236
- ))
259
+ created_at tags
260
+ ])
237
261
 
238
262
  def retry_extra_items(retry_job)
239
263
  @retry_extra_items ||= {}.tap do |extra|
@@ -250,8 +274,8 @@ module Sidekiq
250
274
  return number
251
275
  end
252
276
 
253
- options = {delimiter: ',', separator: '.'}
254
- parts = number.to_s.to_str.split('.')
277
+ options = {delimiter: ",", separator: "."}
278
+ parts = number.to_s.to_str.split(".")
255
279
  parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
256
280
  parts.join(options[:separator])
257
281
  end
@@ -259,8 +283,8 @@ module Sidekiq
259
283
  def h(text)
260
284
  ::Rack::Utils.escape_html(text)
261
285
  rescue ArgumentError => e
262
- raise unless e.message.eql?('invalid byte sequence in UTF-8')
263
- text.encode!('UTF-16', 'UTF-8', invalid: :replace, replace: '').encode!('UTF-8', 'UTF-16')
286
+ raise unless e.message.eql?("invalid byte sequence in UTF-8")
287
+ text.encode!("UTF-16", "UTF-8", invalid: :replace, replace: "").encode!("UTF-8", "UTF-16")
264
288
  retry
265
289
  end
266
290
 
@@ -277,7 +301,7 @@ module Sidekiq
277
301
  end
278
302
 
279
303
  def environment_title_prefix
280
- environment = Sidekiq.options[:environment] || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
304
+ environment = Sidekiq.options[:environment] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
281
305
 
282
306
  "[#{environment.upcase}] " unless environment == "production"
283
307
  end
@@ -287,30 +311,30 @@ module Sidekiq
287
311
  end
288
312
 
289
313
  def server_utc_time
290
- Time.now.utc.strftime('%H:%M:%S UTC')
314
+ Time.now.utc.strftime("%H:%M:%S UTC")
291
315
  end
292
316
 
293
317
  def redis_connection_and_namespace
294
318
  @redis_connection_and_namespace ||= begin
295
- namespace_suffix = namespace == nil ? '' : "##{namespace}"
319
+ namespace_suffix = namespace.nil? ? "" : "##{namespace}"
296
320
  "#{redis_connection}#{namespace_suffix}"
297
321
  end
298
322
  end
299
323
 
300
324
  def retry_or_delete_or_kill(job, params)
301
- if params['retry']
325
+ if params["retry"]
302
326
  job.retry
303
- elsif params['delete']
327
+ elsif params["delete"]
304
328
  job.delete
305
- elsif params['kill']
329
+ elsif params["kill"]
306
330
  job.kill
307
331
  end
308
332
  end
309
333
 
310
334
  def delete_or_add_queue(job, params)
311
- if params['delete']
335
+ if params["delete"]
312
336
  job.delete
313
- elsif params['add_to_queue']
337
+ elsif params["add_to_queue"]
314
338
  job.add_to_queue
315
339
  end
316
340
  end