sidekiq 5.2.5 → 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 (79) 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 +130 -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 +19 -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 +61 -42
  21. data/lib/sidekiq/api.rb +220 -192
  22. data/lib/sidekiq/cli.rb +111 -174
  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 +71 -60
  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 +133 -0
  39. data/lib/sidekiq/paginator.rb +18 -14
  40. data/lib/sidekiq/processor.rb +83 -75
  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 -16
  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 +64 -66
  51. data/lib/sidekiq/web/helpers.rb +89 -71
  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/de.yml +14 -2
  60. data/web/locales/ja.yml +2 -1
  61. data/web/views/_job_info.erb +2 -1
  62. data/web/views/busy.erb +4 -1
  63. data/web/views/dead.erb +2 -2
  64. data/web/views/layout.erb +1 -0
  65. data/web/views/morgue.erb +4 -1
  66. data/web/views/queue.erb +10 -1
  67. data/web/views/queues.erb +1 -1
  68. data/web/views/retries.erb +4 -1
  69. data/web/views/retry.erb +2 -2
  70. data/web/views/scheduled.erb +4 -1
  71. metadata +21 -32
  72. data/.travis.yml +0 -17
  73. data/Appraisals +0 -9
  74. data/bin/sidekiqctl +0 -237
  75. data/gemfiles/rails_4.gemfile +0 -31
  76. data/gemfiles/rails_5.gemfile +0 -31
  77. data/lib/sidekiq/core_ext.rb +0 -1
  78. data/lib/sidekiq/logging.rb +0 -122
  79. 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}")
@@ -5,8 +5,7 @@ module Sidekiq
5
5
  extend WebRouter
6
6
 
7
7
  CONTENT_LENGTH = "Content-Length"
8
- CONTENT_TYPE = "Content-Type"
9
- REDIS_KEYS = %w(redis_version uptime_in_days connected_clients used_memory_human used_memory_peak_human)
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:",
12
11
  "child-src 'self'",
@@ -20,8 +19,8 @@ module Sidekiq
20
19
  "script-src 'self' https: http: 'unsafe-inline'",
21
20
  "style-src 'self' https: http: 'unsafe-inline'",
22
21
  "worker-src 'self'",
23
- "base-uri 'self'"
24
- ].join('; ').freeze
22
+ "base-uri 'self'",
23
+ ].join("; ").freeze
25
24
 
26
25
  def initialize(klass)
27
26
  @klass = klass
@@ -44,8 +43,8 @@ module Sidekiq
44
43
  end
45
44
 
46
45
  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)
46
+ @redis_info = redis_info.select { |k, v| REDIS_KEYS.include? k }
47
+ stats_history = Sidekiq::Stats::History.new((params["days"] || 30).to_i)
49
48
  @processed_history = stats_history.processed
50
49
  @failed_history = stats_history.failed
51
50
 
@@ -57,14 +56,14 @@ module Sidekiq
57
56
  end
58
57
 
59
58
  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']
59
+ if params["identity"]
60
+ p = Sidekiq::Process.new("identity" => params["identity"])
61
+ p.quiet! if params["quiet"]
62
+ p.stop! if params["stop"]
64
63
  else
65
64
  processes.each do |pro|
66
- pro.quiet! if params['quiet']
67
- pro.stop! if params['stop']
65
+ pro.quiet! if params["quiet"]
66
+ pro.stop! if params["stop"]
68
67
  end
69
68
  end
70
69
 
@@ -82,9 +81,9 @@ module Sidekiq
82
81
 
83
82
  halt(404) unless @name
84
83
 
85
- @count = (params['count'] || 25).to_i
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)
@@ -98,21 +97,22 @@ module Sidekiq
98
97
 
99
98
  post "/queues/:name/delete" do
100
99
  name = route_params[:name]
101
- Sidekiq::Job.new(params['key_val'], name).delete
100
+ Sidekiq::Job.new(params["key_val"], name).delete
102
101
 
103
102
  redirect_with_query("#{root_path}queues/#{CGI.escape(name)}")
104
103
  end
105
104
 
106
- get '/morgue' do
107
- @count = (params['count'] || 25).to_i
108
- (@current_page, @total_size, @dead) = page("dead", params['page'], @count, reverse: true)
105
+ get "/morgue" do
106
+ @count = (params["count"] || 25).to_i
107
+ (@current_page, @total_size, @dead) = page("dead", params["page"], @count, reverse: true)
109
108
  @dead = @dead.map { |msg, score| Sidekiq::SortedEntry.new(nil, score, msg) }
110
109
 
111
110
  erb(:morgue)
112
111
  end
113
112
 
114
113
  get "/morgue/:key" do
115
- halt(404) unless key = route_params[:key]
114
+ key = route_params[:key]
115
+ halt(404) unless key
116
116
 
117
117
  @dead = Sidekiq::DeadSet.new.fetch(*parse_params(key)).first
118
118
 
@@ -123,10 +123,10 @@ module Sidekiq
123
123
  end
124
124
  end
125
125
 
126
- post '/morgue' do
127
- redirect(request.path) unless params['key']
126
+ post "/morgue" do
127
+ redirect(request.path) unless params["key"]
128
128
 
129
- params['key'].each do |key|
129
+ params["key"].each do |key|
130
130
  job = Sidekiq::DeadSet.new.fetch(*parse_params(key)).first
131
131
  retry_or_delete_or_kill job, params if job
132
132
  end
@@ -147,7 +147,8 @@ module Sidekiq
147
147
  end
148
148
 
149
149
  post "/morgue/:key" do
150
- halt(404) unless key = route_params[:key]
150
+ key = route_params[:key]
151
+ halt(404) unless key
151
152
 
152
153
  job = Sidekiq::DeadSet.new.fetch(*parse_params(key)).first
153
154
  retry_or_delete_or_kill job, params if job
@@ -155,9 +156,9 @@ module Sidekiq
155
156
  redirect_with_query("#{root_path}morgue")
156
157
  end
157
158
 
158
- get '/retries' do
159
- @count = (params['count'] || 25).to_i
160
- (@current_page, @total_size, @retries) = page("retry", params['page'], @count)
159
+ get "/retries" do
160
+ @count = (params["count"] || 25).to_i
161
+ (@current_page, @total_size, @retries) = page("retry", params["page"], @count)
161
162
  @retries = @retries.map { |msg, score| Sidekiq::SortedEntry.new(nil, score, msg) }
162
163
 
163
164
  erb(:retries)
@@ -173,10 +174,10 @@ module Sidekiq
173
174
  end
174
175
  end
175
176
 
176
- post '/retries' do
177
- redirect(request.path) unless params['key']
177
+ post "/retries" do
178
+ redirect(request.path) unless params["key"]
178
179
 
179
- params['key'].each do |key|
180
+ params["key"].each do |key|
180
181
  job = Sidekiq::RetrySet.new.fetch(*parse_params(key)).first
181
182
  retry_or_delete_or_kill job, params if job
182
183
  end
@@ -210,9 +211,9 @@ module Sidekiq
210
211
  redirect_with_query("#{root_path}retries")
211
212
  end
212
213
 
213
- get '/scheduled' do
214
- @count = (params['count'] || 25).to_i
215
- (@current_page, @total_size, @scheduled) = page("schedule", params['page'], @count)
214
+ get "/scheduled" do
215
+ @count = (params["count"] || 25).to_i
216
+ (@current_page, @total_size, @scheduled) = page("schedule", params["page"], @count)
216
217
  @scheduled = @scheduled.map { |msg, score| Sidekiq::SortedEntry.new(nil, score, msg) }
217
218
 
218
219
  erb(:scheduled)
@@ -228,10 +229,10 @@ module Sidekiq
228
229
  end
229
230
  end
230
231
 
231
- post '/scheduled' do
232
- redirect(request.path) unless params['key']
232
+ post "/scheduled" do
233
+ redirect(request.path) unless params["key"]
233
234
 
234
- params['key'].each do |key|
235
+ params["key"].each do |key|
235
236
  job = Sidekiq::ScheduledSet.new.fetch(*parse_params(key)).first
236
237
  delete_or_add_queue job, params if job
237
238
  end
@@ -240,7 +241,8 @@ module Sidekiq
240
241
  end
241
242
 
242
243
  post "/scheduled/:key" do
243
- halt(404) unless key = route_params[:key]
244
+ key = route_params[:key]
245
+ halt(404) unless key
244
246
 
245
247
  job = Sidekiq::ScheduledSet.new.fetch(*parse_params(key)).first
246
248
  delete_or_add_queue job, params if job
@@ -248,48 +250,44 @@ module Sidekiq
248
250
  redirect_with_query("#{root_path}scheduled")
249
251
  end
250
252
 
251
- get '/dashboard/stats' do
253
+ get "/dashboard/stats" do
252
254
  redirect "#{root_path}stats"
253
255
  end
254
256
 
255
- get '/stats' do
257
+ get "/stats" do
256
258
  sidekiq_stats = Sidekiq::Stats.new
257
- redis_stats = redis_info.select { |k, v| REDIS_KEYS.include? k }
259
+ redis_stats = redis_info.select { |k, v| REDIS_KEYS.include? k }
258
260
  json(
259
261
  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
262
+ processed: sidekiq_stats.processed,
263
+ failed: sidekiq_stats.failed,
264
+ busy: sidekiq_stats.workers_size,
265
+ processes: sidekiq_stats.processes_size,
266
+ enqueued: sidekiq_stats.enqueued,
267
+ scheduled: sidekiq_stats.scheduled_size,
268
+ retries: sidekiq_stats.retry_size,
269
+ dead: sidekiq_stats.dead_size,
270
+ default_latency: sidekiq_stats.default_queue_latency,
269
271
  },
270
272
  redis: redis_stats,
271
273
  server_utc_time: server_utc_time
272
274
  )
273
275
  end
274
276
 
275
- get '/stats/queues' do
277
+ get "/stats/queues" do
276
278
  json Sidekiq::Stats::Queues.new.lengths
277
279
  end
278
280
 
279
281
  def call(env)
280
282
  action = self.class.match(env)
281
- return [404, {"Content-Type" => "text/plain", "X-Cascade" => "pass" }, ["Not Found"]] unless action
283
+ return [404, {"Content-Type" => "text/plain", "X-Cascade" => "pass"}, ["Not Found"]] unless action
282
284
 
283
- resp = catch(:halt) do
284
- app = @klass
285
+ app = @klass
286
+ resp = catch(:halt) do # rubocop:disable Standard/SemanticBlocks
285
287
  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
288
+ action.instance_exec env, &action.block
289
+ ensure
290
+ self.class.run_afters(app, action)
293
291
  end
294
292
 
295
293
  resp = case resp
@@ -300,7 +298,7 @@ module Sidekiq
300
298
  "Content-Type" => "text/html",
301
299
  "Cache-Control" => "no-cache",
302
300
  "Content-Language" => action.locale,
303
- "Content-Security-Policy" => CSP_HEADER
301
+ "Content-Security-Policy" => CSP_HEADER,
304
302
  }
305
303
 
306
304
  [200, headers, [resp]]
@@ -308,12 +306,12 @@ module Sidekiq
308
306
 
309
307
  resp[1] = resp[1].dup
310
308
 
311
- 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
312
310
 
313
311
  resp
314
312
  end
315
313
 
316
- def self.helpers(mod=nil, &block)
314
+ def self.helpers(mod = nil, &block)
317
315
  if block_given?
318
316
  WebAction.class_eval(&block)
319
317
  else
@@ -321,11 +319,11 @@ module Sidekiq
321
319
  end
322
320
  end
323
321
 
324
- def self.before(path=nil, &block)
322
+ def self.before(path = nil, &block)
325
323
  befores << [path && Regexp.new("\\A#{path.gsub("*", ".*")}\\z"), block]
326
324
  end
327
325
 
328
- def self.after(path=nil, &block)
326
+ def self.after(path = nil, &block)
329
327
  afters << [path && Regexp.new("\\A#{path.gsub("*", ".*")}\\z"), block]
330
328
  end
331
329
 
@@ -338,8 +336,8 @@ module Sidekiq
338
336
  end
339
337
 
340
338
  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) }
339
+ hooks.select { |p, _| !p || p =~ action.env[WebRouter::PATH_INFO] }
340
+ .each { |_, b| action.instance_exec(action.env, app, &b) }
343
341
  end
344
342
 
345
343
  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
@@ -141,12 +156,6 @@ module Sidekiq
141
156
  @stats ||= Sidekiq::Stats.new
142
157
  end
143
158
 
144
- def retries_with_score(score)
145
- Sidekiq.redis do |conn|
146
- conn.zrangebyscore('retry', score, score)
147
- end.map { |msg| Sidekiq.load_json(msg) }
148
- end
149
-
150
159
  def redis_connection
151
160
  Sidekiq.redis do |conn|
152
161
  c = conn.connection
@@ -163,24 +172,24 @@ module Sidekiq
163
172
  end
164
173
 
165
174
  def root_path
166
- "#{env['SCRIPT_NAME']}/"
175
+ "#{env["SCRIPT_NAME"]}/"
167
176
  end
168
177
 
169
178
  def current_path
170
- @current_path ||= request.path_info.gsub(/^\//,'')
179
+ @current_path ||= request.path_info.gsub(/^\//, "")
171
180
  end
172
181
 
173
182
  def current_status
174
- workers.size == 0 ? 'idle' : 'active'
183
+ workers.size == 0 ? "idle" : "active"
175
184
  end
176
185
 
177
186
  def relative_time(time)
178
187
  stamp = time.getutc.iso8601
179
- %{<time class="ltr" dir="ltr" title="#{stamp}" datetime="#{stamp}">#{time}</time>}
188
+ %(<time class="ltr" dir="ltr" title="#{stamp}" datetime="#{stamp}">#{time}</time>)
180
189
  end
181
190
 
182
191
  def job_params(job, score)
183
- "#{score}-#{job['jid']}"
192
+ "#{score}-#{job["jid"]}"
184
193
  end
185
194
 
186
195
  def parse_params(params)
@@ -188,7 +197,7 @@ module Sidekiq
188
197
  [score.to_f, jid]
189
198
  end
190
199
 
191
- SAFE_QPARAMS = %w(page poll)
200
+ SAFE_QPARAMS = %w[page poll direction]
192
201
 
193
202
  # Merge options with current params, filter safe params, and stringify to query string
194
203
  def qparams(options)
@@ -197,9 +206,13 @@ module Sidekiq
197
206
  options[key.to_s] = options.delete(key)
198
207
  end
199
208
 
200
- params.merge(options).map do |key, value|
209
+ to_query_string(params.merge(options))
210
+ end
211
+
212
+ def to_query_string(params)
213
+ params.map { |key, value|
201
214
  SAFE_QPARAMS.include?(key) ? "#{key}=#{CGI.escape(value.to_s)}" : next
202
- end.compact.join("&")
215
+ }.compact.join("&")
203
216
  end
204
217
 
205
218
  def truncate(text, truncate_after_chars = 2000)
@@ -207,9 +220,16 @@ module Sidekiq
207
220
  end
208
221
 
209
222
  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(", ")
223
+ return "Invalid job payload, args is nil" if args.nil?
224
+ return "Invalid job payload, args must be an Array, not #{args.class.name}" unless args.is_a?(Array)
225
+
226
+ begin
227
+ args.map { |arg|
228
+ h(truncate(to_display(arg), truncate_after_chars))
229
+ }.join(", ")
230
+ rescue
231
+ "Illegal job arguments: #{h args.inspect}"
232
+ end
213
233
  end
214
234
 
215
235
  def csrf_tag
@@ -217,23 +237,21 @@ module Sidekiq
217
237
  end
218
238
 
219
239
  def to_display(arg)
240
+ arg.inspect
241
+ rescue
220
242
  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
243
+ arg.to_s
244
+ rescue => ex
245
+ "Cannot display argument: [#{ex.class.name}] #{ex.message}"
228
246
  end
229
247
  end
230
248
 
231
- RETRY_JOB_KEYS = Set.new(%w(
249
+ RETRY_JOB_KEYS = Set.new(%w[
232
250
  queue class args retry_count retried_at failed_at
233
251
  jid error_message error_class backtrace
234
252
  error_backtrace enqueued_at retry wrapped
235
- created_at
236
- ))
253
+ created_at tags
254
+ ])
237
255
 
238
256
  def retry_extra_items(retry_job)
239
257
  @retry_extra_items ||= {}.tap do |extra|
@@ -250,8 +268,8 @@ module Sidekiq
250
268
  return number
251
269
  end
252
270
 
253
- options = {delimiter: ',', separator: '.'}
254
- parts = number.to_s.to_str.split('.')
271
+ options = {delimiter: ",", separator: "."}
272
+ parts = number.to_s.to_str.split(".")
255
273
  parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
256
274
  parts.join(options[:separator])
257
275
  end
@@ -259,8 +277,8 @@ module Sidekiq
259
277
  def h(text)
260
278
  ::Rack::Utils.escape_html(text)
261
279
  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')
280
+ raise unless e.message.eql?("invalid byte sequence in UTF-8")
281
+ text.encode!("UTF-16", "UTF-8", invalid: :replace, replace: "").encode!("UTF-8", "UTF-16")
264
282
  retry
265
283
  end
266
284
 
@@ -277,7 +295,7 @@ module Sidekiq
277
295
  end
278
296
 
279
297
  def environment_title_prefix
280
- environment = Sidekiq.options[:environment] || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
298
+ environment = Sidekiq.options[:environment] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
281
299
 
282
300
  "[#{environment.upcase}] " unless environment == "production"
283
301
  end
@@ -287,30 +305,30 @@ module Sidekiq
287
305
  end
288
306
 
289
307
  def server_utc_time
290
- Time.now.utc.strftime('%H:%M:%S UTC')
308
+ Time.now.utc.strftime("%H:%M:%S UTC")
291
309
  end
292
310
 
293
311
  def redis_connection_and_namespace
294
312
  @redis_connection_and_namespace ||= begin
295
- namespace_suffix = namespace == nil ? '' : "##{namespace}"
313
+ namespace_suffix = namespace.nil? ? "" : "##{namespace}"
296
314
  "#{redis_connection}#{namespace_suffix}"
297
315
  end
298
316
  end
299
317
 
300
318
  def retry_or_delete_or_kill(job, params)
301
- if params['retry']
319
+ if params["retry"]
302
320
  job.retry
303
- elsif params['delete']
321
+ elsif params["delete"]
304
322
  job.delete
305
- elsif params['kill']
323
+ elsif params["kill"]
306
324
  job.kill
307
325
  end
308
326
  end
309
327
 
310
328
  def delete_or_add_queue(job, params)
311
- if params['delete']
329
+ if params["delete"]
312
330
  job.delete
313
- elsif params['add_to_queue']
331
+ elsif params["add_to_queue"]
314
332
  job.add_to_queue
315
333
  end
316
334
  end