sidekiq 6.5.12 → 7.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +149 -20
  3. data/README.md +42 -34
  4. data/bin/sidekiq +3 -8
  5. data/bin/sidekiqload +204 -118
  6. data/bin/sidekiqmon +3 -0
  7. data/lib/sidekiq/api.rb +114 -128
  8. data/lib/sidekiq/capsule.rb +127 -0
  9. data/lib/sidekiq/cli.rb +56 -74
  10. data/lib/sidekiq/client.rb +65 -36
  11. data/lib/sidekiq/component.rb +4 -1
  12. data/lib/sidekiq/config.rb +282 -0
  13. data/lib/sidekiq/deploy.rb +62 -0
  14. data/lib/sidekiq/embedded.rb +61 -0
  15. data/lib/sidekiq/fetch.rb +11 -14
  16. data/lib/sidekiq/job.rb +371 -10
  17. data/lib/sidekiq/job_logger.rb +2 -2
  18. data/lib/sidekiq/job_retry.rb +33 -15
  19. data/lib/sidekiq/job_util.rb +51 -15
  20. data/lib/sidekiq/launcher.rb +66 -62
  21. data/lib/sidekiq/logger.rb +1 -26
  22. data/lib/sidekiq/manager.rb +9 -11
  23. data/lib/sidekiq/metrics/query.rb +3 -3
  24. data/lib/sidekiq/metrics/shared.rb +8 -7
  25. data/lib/sidekiq/metrics/tracking.rb +20 -18
  26. data/lib/sidekiq/middleware/chain.rb +19 -18
  27. data/lib/sidekiq/middleware/current_attributes.rb +52 -20
  28. data/lib/sidekiq/monitor.rb +16 -3
  29. data/lib/sidekiq/paginator.rb +1 -1
  30. data/lib/sidekiq/processor.rb +46 -51
  31. data/lib/sidekiq/rails.rb +8 -7
  32. data/lib/sidekiq/redis_client_adapter.rb +10 -69
  33. data/lib/sidekiq/redis_connection.rb +12 -111
  34. data/lib/sidekiq/scheduled.rb +21 -22
  35. data/lib/sidekiq/testing.rb +6 -34
  36. data/lib/sidekiq/transaction_aware_client.rb +4 -5
  37. data/lib/sidekiq/version.rb +2 -1
  38. data/lib/sidekiq/web/action.rb +3 -3
  39. data/lib/sidekiq/web/application.rb +76 -11
  40. data/lib/sidekiq/web/csrf_protection.rb +2 -2
  41. data/lib/sidekiq/web/helpers.rb +39 -24
  42. data/lib/sidekiq/web.rb +17 -16
  43. data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
  44. data/lib/sidekiq.rb +76 -274
  45. data/sidekiq.gemspec +12 -10
  46. data/web/assets/javascripts/application.js +18 -0
  47. data/web/assets/javascripts/base-charts.js +106 -0
  48. data/web/assets/javascripts/dashboard-charts.js +168 -0
  49. data/web/assets/javascripts/dashboard.js +3 -223
  50. data/web/assets/javascripts/metrics.js +117 -115
  51. data/web/assets/stylesheets/application-dark.css +4 -0
  52. data/web/assets/stylesheets/application-rtl.css +2 -91
  53. data/web/assets/stylesheets/application.css +23 -298
  54. data/web/locales/ar.yml +70 -70
  55. data/web/locales/cs.yml +62 -62
  56. data/web/locales/da.yml +60 -53
  57. data/web/locales/de.yml +65 -65
  58. data/web/locales/el.yml +2 -7
  59. data/web/locales/en.yml +78 -70
  60. data/web/locales/es.yml +68 -68
  61. data/web/locales/fa.yml +65 -65
  62. data/web/locales/fr.yml +81 -67
  63. data/web/locales/gd.yml +99 -0
  64. data/web/locales/he.yml +65 -64
  65. data/web/locales/hi.yml +59 -59
  66. data/web/locales/it.yml +53 -53
  67. data/web/locales/ja.yml +67 -69
  68. data/web/locales/ko.yml +52 -52
  69. data/web/locales/lt.yml +66 -66
  70. data/web/locales/nb.yml +61 -61
  71. data/web/locales/nl.yml +52 -52
  72. data/web/locales/pl.yml +45 -45
  73. data/web/locales/pt-br.yml +79 -69
  74. data/web/locales/pt.yml +51 -51
  75. data/web/locales/ru.yml +67 -66
  76. data/web/locales/sv.yml +53 -53
  77. data/web/locales/ta.yml +60 -60
  78. data/web/locales/uk.yml +62 -61
  79. data/web/locales/ur.yml +64 -64
  80. data/web/locales/vi.yml +67 -67
  81. data/web/locales/zh-cn.yml +20 -18
  82. data/web/locales/zh-tw.yml +10 -1
  83. data/web/views/_footer.erb +5 -2
  84. data/web/views/_job_info.erb +18 -2
  85. data/web/views/_metrics_period_select.erb +12 -0
  86. data/web/views/_paging.erb +2 -0
  87. data/web/views/_poll_link.erb +1 -1
  88. data/web/views/busy.erb +39 -28
  89. data/web/views/dashboard.erb +36 -5
  90. data/web/views/filtering.erb +7 -0
  91. data/web/views/metrics.erb +33 -20
  92. data/web/views/metrics_for_job.erb +25 -44
  93. data/web/views/morgue.erb +5 -9
  94. data/web/views/queue.erb +10 -14
  95. data/web/views/queues.erb +3 -1
  96. data/web/views/retries.erb +5 -9
  97. data/web/views/scheduled.erb +12 -13
  98. metadata +44 -39
  99. data/lib/sidekiq/delay.rb +0 -43
  100. data/lib/sidekiq/extensions/action_mailer.rb +0 -48
  101. data/lib/sidekiq/extensions/active_record.rb +0 -43
  102. data/lib/sidekiq/extensions/class_methods.rb +0 -43
  103. data/lib/sidekiq/extensions/generic_proxy.rb +0 -33
  104. data/lib/sidekiq/metrics/deploy.rb +0 -47
  105. data/lib/sidekiq/worker.rb +0 -370
  106. data/web/assets/javascripts/graph.js +0 -16
  107. /data/{LICENSE → LICENSE.txt} +0 -0
@@ -8,16 +8,20 @@ module Sidekiq
8
8
  SETS = %w[retry schedule]
9
9
 
10
10
  class Enq
11
+ include Sidekiq::Component
12
+
11
13
  LUA_ZPOPBYSCORE = <<~LUA
12
14
  local key, now = KEYS[1], ARGV[1]
13
- local jobs = redis.call("zrangebyscore", key, "-inf", now, "limit", 0, 1)
15
+ local jobs = redis.call("zrange", key, "-inf", now, "byscore", "limit", 0, 1)
14
16
  if jobs[1] then
15
17
  redis.call("zrem", key, jobs[1])
16
18
  return jobs[1]
17
19
  end
18
20
  LUA
19
21
 
20
- def initialize
22
+ def initialize(container)
23
+ @config = container
24
+ @client = Sidekiq::Client.new(config: container)
21
25
  @done = false
22
26
  @lua_zpopbyscore_sha = nil
23
27
  end
@@ -25,15 +29,15 @@ module Sidekiq
25
29
  def enqueue_jobs(sorted_sets = SETS)
26
30
  # A job's "score" in Redis is the time at which it should be processed.
27
31
  # Just check Redis for the set of jobs with a timestamp before now.
28
- Sidekiq.redis do |conn|
32
+ redis do |conn|
29
33
  sorted_sets.each do |sorted_set|
30
34
  # Get next item in the queue with score (time to execute) <= now.
31
35
  # We need to go through the list one at a time to reduce the risk of something
32
36
  # going wrong between the time jobs are popped from the scheduled queue and when
33
37
  # they are pushed onto a work queue and losing the jobs.
34
38
  while !@done && (job = zpopbyscore(conn, keys: [sorted_set], argv: [Time.now.to_f.to_s]))
35
- Sidekiq::Client.push(Sidekiq.load_json(job))
36
- Sidekiq.logger.debug { "enqueued #{sorted_set}: #{job}" }
39
+ @client.push(Sidekiq.load_json(job))
40
+ logger.debug { "enqueued #{sorted_set}: #{job}" }
37
41
  end
38
42
  end
39
43
  end
@@ -47,12 +51,11 @@ module Sidekiq
47
51
 
48
52
  def zpopbyscore(conn, keys: nil, argv: nil)
49
53
  if @lua_zpopbyscore_sha.nil?
50
- raw_conn = conn.respond_to?(:redis) ? conn.redis : conn
51
- @lua_zpopbyscore_sha = raw_conn.script(:load, LUA_ZPOPBYSCORE)
54
+ @lua_zpopbyscore_sha = conn.script(:load, LUA_ZPOPBYSCORE)
52
55
  end
53
56
 
54
- conn.evalsha(@lua_zpopbyscore_sha, keys, argv)
55
- rescue RedisConnection.adapter::CommandError => e
57
+ conn.call("EVALSHA", @lua_zpopbyscore_sha, keys.size, *keys, *argv)
58
+ rescue RedisClient::CommandError => e
56
59
  raise unless e.message.start_with?("NOSCRIPT")
57
60
 
58
61
  @lua_zpopbyscore_sha = nil
@@ -70,9 +73,9 @@ module Sidekiq
70
73
 
71
74
  INITIAL_WAIT = 10
72
75
 
73
- def initialize(options)
74
- @config = options
75
- @enq = (options[:scheduled_enq] || Sidekiq::Scheduled::Enq).new
76
+ def initialize(config)
77
+ @config = config
78
+ @enq = (config[:scheduled_enq] || Sidekiq::Scheduled::Enq).new(config)
76
79
  @sleeper = ConnectionPool::TimedStack.new
77
80
  @done = false
78
81
  @thread = nil
@@ -82,14 +85,10 @@ module Sidekiq
82
85
  # Shut down this instance, will pause until the thread is dead.
83
86
  def terminate
84
87
  @done = true
85
- @enq.terminate if @enq.respond_to?(:terminate)
88
+ @enq.terminate
86
89
 
87
- if @thread
88
- t = @thread
89
- @thread = nil
90
- @sleeper << 0
91
- t.value
92
- end
90
+ @sleeper << 0
91
+ @thread&.value
93
92
  end
94
93
 
95
94
  def start
@@ -194,11 +193,11 @@ module Sidekiq
194
193
  # should never depend on sidekiq/api.
195
194
  def cleanup
196
195
  # dont run cleanup more than once per minute
197
- return 0 unless Sidekiq.redis { |conn| conn.set("process_cleanup", "1", nx: true, ex: 60) }
196
+ return 0 unless redis { |conn| conn.set("process_cleanup", "1", nx: true, ex: 60) }
198
197
 
199
198
  count = 0
200
- Sidekiq.redis do |conn|
201
- procs = conn.sscan_each("processes").to_a
199
+ redis do |conn|
200
+ procs = conn.sscan("processes").to_a
202
201
  heartbeats = conn.pipelined { |pipeline|
203
202
  procs.each do |key|
204
203
  pipeline.hget(key, "info")
@@ -51,19 +51,10 @@ module Sidekiq
51
51
  end
52
52
 
53
53
  def server_middleware
54
- @server_chain ||= Middleware::Chain.new
54
+ @server_chain ||= Middleware::Chain.new(Sidekiq.default_configuration)
55
55
  yield @server_chain if block_given?
56
56
  @server_chain
57
57
  end
58
-
59
- def constantize(str)
60
- names = str.split("::")
61
- names.shift if names.empty? || names.first.empty?
62
-
63
- names.inject(Object) do |constant, name|
64
- constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
65
- end
66
- end
67
58
  end
68
59
  end
69
60
 
@@ -73,7 +64,7 @@ module Sidekiq
73
64
  class EmptyQueueError < RuntimeError; end
74
65
 
75
66
  module TestingClient
76
- def raw_push(payloads)
67
+ def atomic_push(conn, payloads)
77
68
  if Sidekiq::Testing.fake?
78
69
  payloads.each do |job|
79
70
  job = Sidekiq.load_json(Sidekiq.dump_json(job))
@@ -83,7 +74,7 @@ module Sidekiq
83
74
  true
84
75
  elsif Sidekiq::Testing.inline?
85
76
  payloads.each do |job|
86
- klass = Sidekiq::Testing.constantize(job["class"])
77
+ klass = Object.const_get(job["class"])
87
78
  job["id"] ||= SecureRandom.hex(12)
88
79
  job_hash = Sidekiq.load_json(Sidekiq.dump_json(job))
89
80
  klass.process_job(job_hash)
@@ -218,25 +209,9 @@ module Sidekiq
218
209
  # assert_equal 1, HardJob.jobs.size
219
210
  # assert_equal :something, HardJob.jobs[0]['args'][0]
220
211
  #
221
- # assert_equal 0, Sidekiq::Extensions::DelayedMailer.jobs.size
222
- # MyMailer.delay.send_welcome_email('foo@example.com')
223
- # assert_equal 1, Sidekiq::Extensions::DelayedMailer.jobs.size
224
- #
225
212
  # You can also clear and drain all job types:
226
213
  #
227
- # assert_equal 0, Sidekiq::Extensions::DelayedMailer.jobs.size
228
- # assert_equal 0, Sidekiq::Extensions::DelayedModel.jobs.size
229
- #
230
- # MyMailer.delay.send_welcome_email('foo@example.com')
231
- # MyModel.delay.do_something_hard
232
- #
233
- # assert_equal 1, Sidekiq::Extensions::DelayedMailer.jobs.size
234
- # assert_equal 1, Sidekiq::Extensions::DelayedModel.jobs.size
235
- #
236
- # Sidekiq::Worker.clear_all # or .drain_all
237
- #
238
- # assert_equal 0, Sidekiq::Extensions::DelayedMailer.jobs.size
239
- # assert_equal 0, Sidekiq::Extensions::DelayedModel.jobs.size
214
+ # Sidekiq::Job.clear_all # or .drain_all
240
215
  #
241
216
  # This can be useful to make sure jobs don't linger between tests:
242
217
  #
@@ -318,7 +293,7 @@ module Sidekiq
318
293
  job_classes = jobs.map { |job| job["class"] }.uniq
319
294
 
320
295
  job_classes.each do |job_class|
321
- Sidekiq::Testing.constantize(job_class).drain
296
+ Object.const_get(job_class).drain
322
297
  end
323
298
  end
324
299
  end
@@ -329,13 +304,10 @@ module Sidekiq
329
304
  def jobs_for(klass)
330
305
  jobs.select do |job|
331
306
  marshalled = job["args"][0]
332
- marshalled.index(klass.to_s) && YAML.load(marshalled)[0] == klass
307
+ marshalled.index(klass.to_s) && YAML.safe_load(marshalled)[0] == klass
333
308
  end
334
309
  end
335
310
  end
336
-
337
- Sidekiq::Extensions::DelayedMailer.extend(TestingExtensions) if defined?(Sidekiq::Extensions::DelayedMailer)
338
- Sidekiq::Extensions::DelayedModel.extend(TestingExtensions) if defined?(Sidekiq::Extensions::DelayedModel)
339
311
  end
340
312
 
341
313
  if defined?(::Rails) && Rails.respond_to?(:env) && !Rails.env.test? && !$TESTING
@@ -5,8 +5,8 @@ require "sidekiq/client"
5
5
 
6
6
  module Sidekiq
7
7
  class TransactionAwareClient
8
- def initialize(redis_pool)
9
- @redis_client = Client.new(redis_pool)
8
+ def initialize(pool: nil, config: nil)
9
+ @redis_client = Client.new(pool: pool, config: config)
10
10
  end
11
11
 
12
12
  def push(item)
@@ -34,11 +34,10 @@ module Sidekiq
34
34
  begin
35
35
  require "after_commit_everywhere"
36
36
  rescue LoadError
37
- Sidekiq.logger.error("You need to add after_commit_everywhere to your Gemfile to use Sidekiq's transactional client")
38
- raise
37
+ raise %q(You need to add `gem "after_commit_everywhere"` to your Gemfile to use Sidekiq's transactional client)
39
38
  end
40
39
 
41
- default_job_options["client_class"] = Sidekiq::TransactionAwareClient
40
+ Sidekiq.default_job_options["client_class"] = Sidekiq::TransactionAwareClient
42
41
  Sidekiq::JobUtil::TRANSIENT_ATTRIBUTES << "client_class"
43
42
  true
44
43
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sidekiq
4
- VERSION = "6.5.12"
4
+ VERSION = "7.1.5"
5
+ MAJOR = 7
5
6
  end
@@ -15,11 +15,11 @@ module Sidekiq
15
15
  end
16
16
 
17
17
  def halt(res)
18
- throw :halt, [res, {"content-type" => "text/plain"}, [res.to_s]]
18
+ throw :halt, [res, {Rack::CONTENT_TYPE => "text/plain"}, [res.to_s]]
19
19
  end
20
20
 
21
21
  def redirect(location)
22
- throw :halt, [302, {"location" => "#{request.base_url}#{location}"}, []]
22
+ throw :halt, [302, {Web::LOCATION => "#{request.base_url}#{location}"}, []]
23
23
  end
24
24
 
25
25
  def params
@@ -68,7 +68,7 @@ module Sidekiq
68
68
  end
69
69
 
70
70
  def json(payload)
71
- [200, {"content-type" => "application/json", "cache-control" => "private, no-store"}, [Sidekiq.dump_json(payload)]]
71
+ [200, {Rack::CONTENT_TYPE => "application/json", Rack::CACHE_CONTROL => "private, no-store"}, [Sidekiq.dump_json(payload)]]
72
72
  end
73
73
 
74
74
  def initialize(env, block)
@@ -20,6 +20,12 @@ module Sidekiq
20
20
  "worker-src 'self'",
21
21
  "base-uri 'self'"
22
22
  ].join("; ").freeze
23
+ METRICS_PERIODS = {
24
+ "1h" => 60,
25
+ "2h" => 120,
26
+ "4h" => 240,
27
+ "8h" => 480
28
+ }
23
29
 
24
30
  def initialize(klass)
25
31
  @klass = klass
@@ -62,14 +68,20 @@ module Sidekiq
62
68
 
63
69
  get "/metrics" do
64
70
  q = Sidekiq::Metrics::Query.new
65
- @query_result = q.top_jobs
71
+ @period = h((params[:period] || "")[0..1])
72
+ @periods = METRICS_PERIODS
73
+ minutes = @periods.fetch(@period, @periods.values.first)
74
+ @query_result = q.top_jobs(minutes: minutes)
66
75
  erb(:metrics)
67
76
  end
68
77
 
69
78
  get "/metrics/:name" do
70
79
  @name = route_params[:name]
80
+ @period = h((params[:period] || "")[0..1])
71
81
  q = Sidekiq::Metrics::Query.new
72
- @query_result = q.for_job(@name)
82
+ @periods = METRICS_PERIODS
83
+ minutes = @periods.fetch(@period, @periods.values.first)
84
+ @query_result = q.for_job(@name, minutes: minutes)
73
85
  erb(:metrics_for_job)
74
86
  end
75
87
 
@@ -82,11 +94,14 @@ module Sidekiq
82
94
 
83
95
  post "/busy" do
84
96
  if params["identity"]
85
- p = Sidekiq::Process.new("identity" => params["identity"])
86
- p.quiet! if params["quiet"]
87
- p.stop! if params["stop"]
97
+ pro = Sidekiq::ProcessSet[params["identity"]]
98
+
99
+ pro.quiet! if params["quiet"]
100
+ pro.stop! if params["stop"]
88
101
  else
89
102
  processes.each do |pro|
103
+ next if pro.embedded?
104
+
90
105
  pro.quiet! if params["quiet"]
91
106
  pro.stop! if params["stop"]
92
107
  end
@@ -310,12 +325,62 @@ module Sidekiq
310
325
  end
311
326
 
312
327
  get "/stats/queues" do
313
- json Sidekiq::Stats::Queues.new.lengths
328
+ json Sidekiq::Stats.new.queues
329
+ end
330
+
331
+ ########
332
+ # Filtering
333
+ get "/filter/retries" do
334
+ x = params[:substr]
335
+ return redirect "#{root_path}retries" unless x && x != ""
336
+
337
+ @retries = search(Sidekiq::RetrySet.new, params[:substr])
338
+ erb :retries
339
+ end
340
+
341
+ post "/filter/retries" do
342
+ x = params[:substr]
343
+ return redirect "#{root_path}retries" unless x && x != ""
344
+
345
+ @retries = search(Sidekiq::RetrySet.new, params[:substr])
346
+ erb :retries
347
+ end
348
+
349
+ get "/filter/scheduled" do
350
+ x = params[:substr]
351
+ return redirect "#{root_path}scheduled" unless x && x != ""
352
+
353
+ @scheduled = search(Sidekiq::ScheduledSet.new, params[:substr])
354
+ erb :scheduled
355
+ end
356
+
357
+ post "/filter/scheduled" do
358
+ x = params[:substr]
359
+ return redirect "#{root_path}scheduled" unless x && x != ""
360
+
361
+ @scheduled = search(Sidekiq::ScheduledSet.new, params[:substr])
362
+ erb :scheduled
363
+ end
364
+
365
+ get "/filter/dead" do
366
+ x = params[:substr]
367
+ return redirect "#{root_path}morgue" unless x && x != ""
368
+
369
+ @dead = search(Sidekiq::DeadSet.new, params[:substr])
370
+ erb :morgue
371
+ end
372
+
373
+ post "/filter/dead" do
374
+ x = params[:substr]
375
+ return redirect "#{root_path}morgue" unless x && x != ""
376
+
377
+ @dead = search(Sidekiq::DeadSet.new, params[:substr])
378
+ erb :morgue
314
379
  end
315
380
 
316
381
  def call(env)
317
382
  action = self.class.match(env)
318
- return [404, {"content-type" => "text/plain", "x-cascade" => "pass"}, ["Not Found"]] unless action
383
+ return [404, {Rack::CONTENT_TYPE => "text/plain", Web::X_CASCADE => "pass"}, ["Not Found"]] unless action
319
384
 
320
385
  app = @klass
321
386
  resp = catch(:halt) do
@@ -332,10 +397,10 @@ module Sidekiq
332
397
  else
333
398
  # rendered content goes here
334
399
  headers = {
335
- "content-type" => "text/html",
336
- "cache-control" => "private, no-store",
337
- "content-language" => action.locale,
338
- "content-security-policy" => CSP_HEADER
400
+ Rack::CONTENT_TYPE => "text/html",
401
+ Rack::CACHE_CONTROL => "private, no-store",
402
+ Web::CONTENT_LANGUAGE => action.locale,
403
+ Web::CONTENT_SECURITY_POLICY => CSP_HEADER
339
404
  }
340
405
  # we'll let Rack calculate Content-Length for us.
341
406
  [200, headers, [resp]]
@@ -62,7 +62,7 @@ module Sidekiq
62
62
 
63
63
  def deny(env)
64
64
  logger(env).warn "attack prevented by #{self.class}"
65
- [403, {"Content-Type" => "text/plain"}, ["Forbidden"]]
65
+ [403, {Rack::CONTENT_TYPE => "text/plain"}, ["Forbidden"]]
66
66
  end
67
67
 
68
68
  def session(env)
@@ -152,7 +152,7 @@ module Sidekiq
152
152
  # value and decrypt it
153
153
  token_length = masked_token.length / 2
154
154
  one_time_pad = masked_token[0...token_length]
155
- encrypted_token = masked_token[token_length..-1]
155
+ encrypted_token = masked_token[token_length..]
156
156
  xor_byte_strings(one_time_pad, encrypted_token)
157
157
  end
158
158
 
@@ -15,7 +15,7 @@ module Sidekiq
15
15
  # so extensions can be localized
16
16
  @strings[lang] ||= settings.locales.each_with_object({}) do |path, global|
17
17
  find_locale_files(lang).each do |file|
18
- strs = YAML.safe_load(File.open(file))
18
+ strs = YAML.safe_load(File.read(file))
19
19
  global.merge!(strs[lang])
20
20
  end
21
21
  end
@@ -49,8 +49,29 @@ module Sidekiq
49
49
  locale_files.select { |file| file =~ /\/#{lang}\.yml$/ }
50
50
  end
51
51
 
52
- # This is a hook for a Sidekiq Pro feature. Please don't touch.
53
- def filtering(*)
52
+ def search(jobset, substr)
53
+ resultset = jobset.scan(substr).to_a
54
+ @current_page = 1
55
+ @count = @total_size = resultset.size
56
+ resultset
57
+ end
58
+
59
+ def filtering(which)
60
+ erb(:filtering, locals: {which: which})
61
+ end
62
+
63
+ def filter_link(jid, within = "retries")
64
+ if within.nil?
65
+ ::Rack::Utils.escape_html(jid)
66
+ else
67
+ "<a href='#{root_path}filter/#{within}?substr=#{jid}'>#{::Rack::Utils.escape_html(jid)}</a>"
68
+ end
69
+ end
70
+
71
+ def display_tags(job, within = "retries")
72
+ job.tags.map { |tag|
73
+ "<span class='label label-info jobtag'>#{filter_link(tag, within)}</span>"
74
+ }.join(" ")
54
75
  end
55
76
 
56
77
  # This view helper provide ability display you html code in
@@ -111,14 +132,7 @@ module Sidekiq
111
132
  end
112
133
  end
113
134
 
114
- # within is used by Sidekiq Pro
115
- def display_tags(job, within = nil)
116
- job.tags.map { |tag|
117
- "<span class='label label-info jobtag'>#{::Rack::Utils.escape_html(tag)}</span>"
118
- }.join(" ")
119
- end
120
-
121
- # mperham/sidekiq#3243
135
+ # sidekiq/sidekiq#3243
122
136
  def unfiltered?
123
137
  yield unless env["PATH_INFO"].start_with?("/filter/")
124
138
  end
@@ -161,22 +175,26 @@ module Sidekiq
161
175
  end
162
176
  end
163
177
 
178
+ def busy_weights(capsule_weights)
179
+ # backwards compat with 7.0.0, remove in 7.1
180
+ cw = [capsule_weights].flatten
181
+ cw.map { |hash|
182
+ hash.map { |name, weight| (weight > 0) ? +name << ": " << weight.to_s : name }.join(", ")
183
+ }.join("; ")
184
+ end
185
+
164
186
  def stats
165
187
  @stats ||= Sidekiq::Stats.new
166
188
  end
167
189
 
168
- def redis_connection
190
+ def redis_url
169
191
  Sidekiq.redis do |conn|
170
- conn.connection[:id]
192
+ conn.config.server_url
171
193
  end
172
194
  end
173
195
 
174
- def namespace
175
- @ns ||= Sidekiq.redis { |conn| conn.respond_to?(:namespace) ? conn.namespace : nil }
176
- end
177
-
178
196
  def redis_info
179
- Sidekiq.redis_info
197
+ Sidekiq.default_configuration.redis_info
180
198
  end
181
199
 
182
200
  def root_path
@@ -314,7 +332,7 @@ module Sidekiq
314
332
  end
315
333
 
316
334
  def environment_title_prefix
317
- environment = Sidekiq[:environment] || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
335
+ environment = Sidekiq.default_configuration[:environment] || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
318
336
 
319
337
  "[#{environment.upcase}] " unless environment == "production"
320
338
  end
@@ -327,11 +345,8 @@ module Sidekiq
327
345
  Time.now.utc.strftime("%H:%M:%S UTC")
328
346
  end
329
347
 
330
- def redis_connection_and_namespace
331
- @redis_connection_and_namespace ||= begin
332
- namespace_suffix = namespace.nil? ? "" : "##{namespace}"
333
- "#{redis_connection}#{namespace_suffix}"
334
- end
348
+ def pollable?
349
+ !(current_path == "" || current_path.start_with?("metrics"))
335
350
  end
336
351
 
337
352
  def retry_or_delete_or_kill(job, params)
data/lib/sidekiq/web.rb CHANGED
@@ -30,11 +30,20 @@ module Sidekiq
30
30
  "Queues" => "queues",
31
31
  "Retries" => "retries",
32
32
  "Scheduled" => "scheduled",
33
- "Dead" => "morgue"
33
+ "Dead" => "morgue",
34
+ "Metrics" => "metrics"
34
35
  }
35
36
 
36
- if ENV["SIDEKIQ_METRICS_BETA"] == "1"
37
- DEFAULT_TABS["Metrics"] = "metrics"
37
+ if Gem::Version.new(Rack::RELEASE) < Gem::Version.new("3")
38
+ CONTENT_LANGUAGE = "Content-Language"
39
+ CONTENT_SECURITY_POLICY = "Content-Security-Policy"
40
+ LOCATION = "Location"
41
+ X_CASCADE = "X-Cascade"
42
+ else
43
+ CONTENT_LANGUAGE = "content-language"
44
+ CONTENT_SECURITY_POLICY = "content-security-policy"
45
+ LOCATION = "location"
46
+ X_CASCADE = "x-cascade"
38
47
  end
39
48
 
40
49
  class << self
@@ -51,6 +60,10 @@ module Sidekiq
51
60
  end
52
61
  alias_method :tabs, :custom_tabs
53
62
 
63
+ def custom_job_info_rows
64
+ @custom_job_info_rows ||= []
65
+ end
66
+
54
67
  def locales
55
68
  @locales ||= LOCALES
56
69
  end
@@ -79,14 +92,6 @@ module Sidekiq
79
92
  send(:"#{attribute}=", value)
80
93
  end
81
94
 
82
- def sessions=(val)
83
- puts "WARNING: Sidekiq::Web.sessions= is no longer relevant and will be removed in Sidekiq 7.0. #{caller(1..1).first}"
84
- end
85
-
86
- def session_secret=(val)
87
- puts "WARNING: Sidekiq::Web.session_secret= is no longer relevant and will be removed in Sidekiq 7.0. #{caller(1..1).first}"
88
- end
89
-
90
95
  attr_accessor :app_url, :redis_pool
91
96
  attr_writer :locales, :views
92
97
  end
@@ -133,10 +138,6 @@ module Sidekiq
133
138
  send(:"#{attribute}=", value)
134
139
  end
135
140
 
136
- def sessions=(val)
137
- puts "Sidekiq::Web#sessions= is no longer relevant and will be removed in Sidekiq 7.0. #{caller[2..2].first}"
138
- end
139
-
140
141
  def self.register(extension)
141
142
  extension.registered(WebApplication)
142
143
  end
@@ -148,7 +149,7 @@ module Sidekiq
148
149
  m = middlewares
149
150
 
150
151
  rules = []
151
- rules = [[:all, {"cache-control" => "public, max-age=86400"}]] unless ENV["SIDEKIQ_WEB_TESTING"]
152
+ rules = [[:all, {Rack::CACHE_CONTROL => "private, max-age=86400"}]] unless ENV["SIDEKIQ_WEB_TESTING"]
152
153
 
153
154
  ::Rack::Builder.new do
154
155
  use Rack::Static, urls: ["/stylesheets", "/images", "/javascripts"],
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sidekiq
4
+ # Sidekiq::Job is a new alias for Sidekiq::Worker as of Sidekiq 6.3.0.
5
+ # Use `include Sidekiq::Job` rather than `include Sidekiq::Worker`.
6
+ #
7
+ # The term "worker" is too generic and overly confusing, used in several
8
+ # different contexts meaning different things. Many people call a Sidekiq
9
+ # process a "worker". Some people call the thread that executes jobs a
10
+ # "worker". This change brings Sidekiq closer to ActiveJob where your job
11
+ # classes extend ApplicationJob.
12
+ Worker = Job
13
+ end