sidekiq 6.5.12 → 7.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +224 -20
  3. data/README.md +43 -35
  4. data/bin/multi_queue_bench +271 -0
  5. data/bin/sidekiq +3 -8
  6. data/bin/sidekiqload +204 -118
  7. data/bin/sidekiqmon +3 -0
  8. data/lib/sidekiq/api.rb +187 -135
  9. data/lib/sidekiq/capsule.rb +127 -0
  10. data/lib/sidekiq/cli.rb +59 -75
  11. data/lib/sidekiq/client.rb +66 -37
  12. data/lib/sidekiq/component.rb +4 -1
  13. data/lib/sidekiq/config.rb +287 -0
  14. data/lib/sidekiq/deploy.rb +62 -0
  15. data/lib/sidekiq/embedded.rb +61 -0
  16. data/lib/sidekiq/fetch.rb +11 -14
  17. data/lib/sidekiq/job.rb +371 -10
  18. data/lib/sidekiq/job_logger.rb +2 -2
  19. data/lib/sidekiq/job_retry.rb +36 -18
  20. data/lib/sidekiq/job_util.rb +51 -15
  21. data/lib/sidekiq/launcher.rb +71 -65
  22. data/lib/sidekiq/logger.rb +2 -27
  23. data/lib/sidekiq/manager.rb +9 -11
  24. data/lib/sidekiq/metrics/query.rb +7 -4
  25. data/lib/sidekiq/metrics/shared.rb +8 -7
  26. data/lib/sidekiq/metrics/tracking.rb +27 -21
  27. data/lib/sidekiq/middleware/chain.rb +19 -18
  28. data/lib/sidekiq/middleware/current_attributes.rb +52 -20
  29. data/lib/sidekiq/monitor.rb +16 -3
  30. data/lib/sidekiq/paginator.rb +2 -2
  31. data/lib/sidekiq/processor.rb +46 -51
  32. data/lib/sidekiq/rails.rb +15 -10
  33. data/lib/sidekiq/redis_client_adapter.rb +23 -66
  34. data/lib/sidekiq/redis_connection.rb +15 -117
  35. data/lib/sidekiq/scheduled.rb +22 -23
  36. data/lib/sidekiq/testing.rb +32 -41
  37. data/lib/sidekiq/transaction_aware_client.rb +11 -5
  38. data/lib/sidekiq/version.rb +2 -1
  39. data/lib/sidekiq/web/action.rb +8 -3
  40. data/lib/sidekiq/web/application.rb +108 -15
  41. data/lib/sidekiq/web/csrf_protection.rb +10 -7
  42. data/lib/sidekiq/web/helpers.rb +52 -38
  43. data/lib/sidekiq/web.rb +17 -16
  44. data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
  45. data/lib/sidekiq.rb +76 -274
  46. data/sidekiq.gemspec +12 -10
  47. data/web/assets/javascripts/application.js +39 -0
  48. data/web/assets/javascripts/base-charts.js +106 -0
  49. data/web/assets/javascripts/dashboard-charts.js +182 -0
  50. data/web/assets/javascripts/dashboard.js +10 -232
  51. data/web/assets/javascripts/metrics.js +151 -115
  52. data/web/assets/stylesheets/application-dark.css +4 -0
  53. data/web/assets/stylesheets/application-rtl.css +10 -89
  54. data/web/assets/stylesheets/application.css +45 -298
  55. data/web/locales/ar.yml +70 -70
  56. data/web/locales/cs.yml +62 -62
  57. data/web/locales/da.yml +60 -53
  58. data/web/locales/de.yml +65 -65
  59. data/web/locales/el.yml +2 -7
  60. data/web/locales/en.yml +78 -70
  61. data/web/locales/es.yml +68 -68
  62. data/web/locales/fa.yml +65 -65
  63. data/web/locales/fr.yml +81 -67
  64. data/web/locales/gd.yml +99 -0
  65. data/web/locales/he.yml +65 -64
  66. data/web/locales/hi.yml +59 -59
  67. data/web/locales/it.yml +53 -53
  68. data/web/locales/ja.yml +67 -69
  69. data/web/locales/ko.yml +52 -52
  70. data/web/locales/lt.yml +66 -66
  71. data/web/locales/nb.yml +61 -61
  72. data/web/locales/nl.yml +52 -52
  73. data/web/locales/pl.yml +45 -45
  74. data/web/locales/pt-br.yml +79 -69
  75. data/web/locales/pt.yml +51 -51
  76. data/web/locales/ru.yml +67 -66
  77. data/web/locales/sv.yml +53 -53
  78. data/web/locales/ta.yml +60 -60
  79. data/web/locales/uk.yml +62 -61
  80. data/web/locales/ur.yml +64 -64
  81. data/web/locales/vi.yml +67 -67
  82. data/web/locales/zh-cn.yml +20 -18
  83. data/web/locales/zh-tw.yml +10 -1
  84. data/web/views/_footer.erb +17 -2
  85. data/web/views/_job_info.erb +18 -2
  86. data/web/views/_metrics_period_select.erb +12 -0
  87. data/web/views/_paging.erb +2 -0
  88. data/web/views/_poll_link.erb +1 -1
  89. data/web/views/_summary.erb +7 -7
  90. data/web/views/busy.erb +46 -35
  91. data/web/views/dashboard.erb +26 -5
  92. data/web/views/filtering.erb +7 -0
  93. data/web/views/metrics.erb +46 -24
  94. data/web/views/metrics_for_job.erb +41 -69
  95. data/web/views/morgue.erb +5 -9
  96. data/web/views/queue.erb +10 -14
  97. data/web/views/queues.erb +9 -3
  98. data/web/views/retries.erb +5 -9
  99. data/web/views/scheduled.erb +12 -13
  100. metadata +44 -38
  101. data/lib/sidekiq/delay.rb +0 -43
  102. data/lib/sidekiq/extensions/action_mailer.rb +0 -48
  103. data/lib/sidekiq/extensions/active_record.rb +0 -43
  104. data/lib/sidekiq/extensions/class_methods.rb +0 -43
  105. data/lib/sidekiq/extensions/generic_proxy.rb +0 -33
  106. data/lib/sidekiq/metrics/deploy.rb +0 -47
  107. data/lib/sidekiq/worker.rb +0 -370
  108. data/web/assets/javascripts/graph.js +0 -16
  109. /data/{LICENSE → LICENSE.txt} +0 -0
@@ -27,7 +27,6 @@
27
27
  # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
28
 
29
29
  require "securerandom"
30
- require "base64"
31
30
  require "rack/request"
32
31
 
33
32
  module Sidekiq
@@ -57,12 +56,12 @@ module Sidekiq
57
56
  end
58
57
 
59
58
  def logger(env)
60
- @logger ||= (env["rack.logger"] || ::Logger.new(env["rack.errors"]))
59
+ @logger ||= env["rack.logger"] || ::Logger.new(env["rack.errors"])
61
60
  end
62
61
 
63
62
  def deny(env)
64
63
  logger(env).warn "attack prevented by #{self.class}"
65
- [403, {"Content-Type" => "text/plain"}, ["Forbidden"]]
64
+ [403, {Rack::CONTENT_TYPE => "text/plain"}, ["Forbidden"]]
66
65
  end
67
66
 
68
67
  def session(env)
@@ -116,7 +115,7 @@ module Sidekiq
116
115
  sess = session(env)
117
116
  localtoken = sess[:csrf]
118
117
 
119
- # Checks that Rack::Session::Cookie actualy contains the csrf toekn
118
+ # Checks that Rack::Session::Cookie actually contains the csrf token
120
119
  return false if localtoken.nil?
121
120
 
122
121
  # Rotate the session token after every use
@@ -143,7 +142,7 @@ module Sidekiq
143
142
  one_time_pad = SecureRandom.random_bytes(token.length)
144
143
  encrypted_token = xor_byte_strings(one_time_pad, token)
145
144
  masked_token = one_time_pad + encrypted_token
146
- Base64.urlsafe_encode64(masked_token)
145
+ encode_token(masked_token)
147
146
  end
148
147
 
149
148
  # Essentially the inverse of +mask_token+.
@@ -152,7 +151,7 @@ module Sidekiq
152
151
  # value and decrypt it
153
152
  token_length = masked_token.length / 2
154
153
  one_time_pad = masked_token[0...token_length]
155
- encrypted_token = masked_token[token_length..-1]
154
+ encrypted_token = masked_token[token_length..]
156
155
  xor_byte_strings(one_time_pad, encrypted_token)
157
156
  end
158
157
 
@@ -168,8 +167,12 @@ module Sidekiq
168
167
  ::Rack::Utils.secure_compare(token.to_s, decode_token(local).to_s)
169
168
  end
170
169
 
170
+ def encode_token(token)
171
+ [token].pack("m0").tr("+/", "-_")
172
+ end
173
+
171
174
  def decode_token(token)
172
- Base64.urlsafe_decode64(token)
175
+ token.tr("-_", "+/").unpack1("m0")
173
176
  end
174
177
 
175
178
  def xor_byte_strings(s1, s2)
@@ -15,12 +15,16 @@ 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
22
22
  end
23
23
 
24
+ def to_json(x)
25
+ Sidekiq.dump_json(x)
26
+ end
27
+
24
28
  def singularize(str, count)
25
29
  if count == 1 && str.respond_to?(:singularize) # rails
26
30
  str.singularize
@@ -49,8 +53,29 @@ module Sidekiq
49
53
  locale_files.select { |file| file =~ /\/#{lang}\.yml$/ }
50
54
  end
51
55
 
52
- # This is a hook for a Sidekiq Pro feature. Please don't touch.
53
- def filtering(*)
56
+ def search(jobset, substr)
57
+ resultset = jobset.scan(substr).to_a
58
+ @current_page = 1
59
+ @count = @total_size = resultset.size
60
+ resultset
61
+ end
62
+
63
+ def filtering(which)
64
+ erb(:filtering, locals: {which: which})
65
+ end
66
+
67
+ def filter_link(jid, within = "retries")
68
+ if within.nil?
69
+ ::Rack::Utils.escape_html(jid)
70
+ else
71
+ "<a href='#{root_path}filter/#{within}?substr=#{jid}'>#{::Rack::Utils.escape_html(jid)}</a>"
72
+ end
73
+ end
74
+
75
+ def display_tags(job, within = "retries")
76
+ job.tags.map { |tag|
77
+ "<span class='label label-info jobtag'>#{filter_link(tag, within)}</span>"
78
+ }.join(" ")
54
79
  end
55
80
 
56
81
  # This view helper provide ability display you html code in
@@ -96,6 +121,10 @@ module Sidekiq
96
121
  #
97
122
  # Inspiration taken from https://github.com/iain/http_accept_language/blob/master/lib/http_accept_language/parser.rb
98
123
  def locale
124
+ # session[:locale] is set via the locale selector from the footer
125
+ # defined?(session) && session are used to avoid exceptions when running tests
126
+ return session[:locale] if defined?(session) && session&.[](:locale)
127
+
99
128
  @locale ||= begin
100
129
  matched_locale = user_preferred_languages.map { |preferred|
101
130
  preferred_language = preferred.split("-", 2).first
@@ -111,14 +140,7 @@ module Sidekiq
111
140
  end
112
141
  end
113
142
 
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
143
+ # sidekiq/sidekiq#3243
122
144
  def unfiltered?
123
145
  yield unless env["PATH_INFO"].start_with?("/filter/")
124
146
  end
@@ -161,22 +183,26 @@ module Sidekiq
161
183
  end
162
184
  end
163
185
 
186
+ def busy_weights(capsule_weights)
187
+ # backwards compat with 7.0.0, remove in 7.1
188
+ cw = [capsule_weights].flatten
189
+ cw.map { |hash|
190
+ hash.map { |name, weight| (weight > 0) ? +name << ": " << weight.to_s : name }.join(", ")
191
+ }.join("; ")
192
+ end
193
+
164
194
  def stats
165
195
  @stats ||= Sidekiq::Stats.new
166
196
  end
167
197
 
168
- def redis_connection
198
+ def redis_url
169
199
  Sidekiq.redis do |conn|
170
- conn.connection[:id]
200
+ conn.config.server_url
171
201
  end
172
202
  end
173
203
 
174
- def namespace
175
- @ns ||= Sidekiq.redis { |conn| conn.respond_to?(:namespace) ? conn.namespace : nil }
176
- end
177
-
178
204
  def redis_info
179
- Sidekiq.redis_info
205
+ Sidekiq.default_configuration.redis_info
180
206
  end
181
207
 
182
208
  def root_path
@@ -274,23 +300,13 @@ module Sidekiq
274
300
  elsif rss_kb < 10_000_000
275
301
  "#{number_with_delimiter((rss_kb / 1024.0).to_i)} MB"
276
302
  else
277
- "#{number_with_delimiter((rss_kb / (1024.0 * 1024.0)).round(1))} GB"
303
+ "#{number_with_delimiter((rss_kb / (1024.0 * 1024.0)), precision: 1)} GB"
278
304
  end
279
305
  end
280
306
 
281
- def number_with_delimiter(number)
282
- return "" if number.nil?
283
-
284
- begin
285
- Float(number)
286
- rescue ArgumentError, TypeError
287
- return number
288
- end
289
-
290
- options = {delimiter: ",", separator: "."}
291
- parts = number.to_s.to_str.split(".")
292
- parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
293
- parts.join(options[:separator])
307
+ def number_with_delimiter(number, options = {})
308
+ precision = options[:precision] || 0
309
+ %(<span data-nwp="#{precision}">#{number.round(precision)}</span>)
294
310
  end
295
311
 
296
312
  def h(text)
@@ -314,7 +330,7 @@ module Sidekiq
314
330
  end
315
331
 
316
332
  def environment_title_prefix
317
- environment = Sidekiq[:environment] || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
333
+ environment = Sidekiq.default_configuration[:environment] || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
318
334
 
319
335
  "[#{environment.upcase}] " unless environment == "production"
320
336
  end
@@ -327,11 +343,9 @@ module Sidekiq
327
343
  Time.now.utc.strftime("%H:%M:%S UTC")
328
344
  end
329
345
 
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
346
+ def pollable?
347
+ # there's no point to refreshing the metrics pages every N seconds
348
+ !(current_path == "" || current_path.index("metrics"))
335
349
  end
336
350
 
337
351
  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