sidekiq 6.5.1 → 7.3.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (125) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +376 -12
  3. data/README.md +43 -35
  4. data/bin/multi_queue_bench +271 -0
  5. data/bin/sidekiq +3 -8
  6. data/bin/sidekiqload +213 -118
  7. data/bin/sidekiqmon +3 -0
  8. data/lib/active_job/queue_adapters/sidekiq_adapter.rb +88 -0
  9. data/lib/generators/sidekiq/job_generator.rb +2 -0
  10. data/lib/sidekiq/api.rb +378 -173
  11. data/lib/sidekiq/capsule.rb +132 -0
  12. data/lib/sidekiq/cli.rb +61 -63
  13. data/lib/sidekiq/client.rb +89 -40
  14. data/lib/sidekiq/component.rb +6 -2
  15. data/lib/sidekiq/config.rb +305 -0
  16. data/lib/sidekiq/deploy.rb +64 -0
  17. data/lib/sidekiq/embedded.rb +63 -0
  18. data/lib/sidekiq/fetch.rb +11 -14
  19. data/lib/sidekiq/iterable_job.rb +55 -0
  20. data/lib/sidekiq/job/interrupt_handler.rb +24 -0
  21. data/lib/sidekiq/job/iterable/active_record_enumerator.rb +53 -0
  22. data/lib/sidekiq/job/iterable/csv_enumerator.rb +47 -0
  23. data/lib/sidekiq/job/iterable/enumerators.rb +135 -0
  24. data/lib/sidekiq/job/iterable.rb +294 -0
  25. data/lib/sidekiq/job.rb +382 -10
  26. data/lib/sidekiq/job_logger.rb +8 -7
  27. data/lib/sidekiq/job_retry.rb +89 -46
  28. data/lib/sidekiq/job_util.rb +53 -15
  29. data/lib/sidekiq/launcher.rb +77 -69
  30. data/lib/sidekiq/logger.rb +2 -27
  31. data/lib/sidekiq/manager.rb +9 -11
  32. data/lib/sidekiq/metrics/query.rb +158 -0
  33. data/lib/sidekiq/metrics/shared.rb +106 -0
  34. data/lib/sidekiq/metrics/tracking.rb +148 -0
  35. data/lib/sidekiq/middleware/chain.rb +84 -48
  36. data/lib/sidekiq/middleware/current_attributes.rb +87 -20
  37. data/lib/sidekiq/middleware/modules.rb +2 -0
  38. data/lib/sidekiq/monitor.rb +19 -5
  39. data/lib/sidekiq/paginator.rb +11 -3
  40. data/lib/sidekiq/processor.rb +67 -56
  41. data/lib/sidekiq/rails.rb +22 -16
  42. data/lib/sidekiq/redis_client_adapter.rb +31 -71
  43. data/lib/sidekiq/redis_connection.rb +44 -117
  44. data/lib/sidekiq/ring_buffer.rb +2 -0
  45. data/lib/sidekiq/scheduled.rb +62 -35
  46. data/lib/sidekiq/systemd.rb +2 -0
  47. data/lib/sidekiq/testing.rb +37 -46
  48. data/lib/sidekiq/transaction_aware_client.rb +11 -5
  49. data/lib/sidekiq/version.rb +6 -1
  50. data/lib/sidekiq/web/action.rb +15 -5
  51. data/lib/sidekiq/web/application.rb +94 -24
  52. data/lib/sidekiq/web/csrf_protection.rb +10 -7
  53. data/lib/sidekiq/web/helpers.rb +118 -45
  54. data/lib/sidekiq/web/router.rb +5 -2
  55. data/lib/sidekiq/web.rb +67 -15
  56. data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
  57. data/lib/sidekiq.rb +78 -266
  58. data/sidekiq.gemspec +12 -10
  59. data/web/assets/javascripts/application.js +46 -1
  60. data/web/assets/javascripts/base-charts.js +106 -0
  61. data/web/assets/javascripts/chart.min.js +13 -0
  62. data/web/assets/javascripts/chartjs-plugin-annotation.min.js +7 -0
  63. data/web/assets/javascripts/dashboard-charts.js +192 -0
  64. data/web/assets/javascripts/dashboard.js +11 -250
  65. data/web/assets/javascripts/metrics.js +298 -0
  66. data/web/assets/stylesheets/application-dark.css +4 -0
  67. data/web/assets/stylesheets/application-rtl.css +10 -89
  68. data/web/assets/stylesheets/application.css +98 -295
  69. data/web/locales/ar.yml +70 -70
  70. data/web/locales/cs.yml +62 -62
  71. data/web/locales/da.yml +60 -53
  72. data/web/locales/de.yml +65 -65
  73. data/web/locales/el.yml +43 -24
  74. data/web/locales/en.yml +83 -69
  75. data/web/locales/es.yml +68 -68
  76. data/web/locales/fa.yml +65 -65
  77. data/web/locales/fr.yml +80 -67
  78. data/web/locales/gd.yml +98 -0
  79. data/web/locales/he.yml +65 -64
  80. data/web/locales/hi.yml +59 -59
  81. data/web/locales/it.yml +85 -54
  82. data/web/locales/ja.yml +72 -68
  83. data/web/locales/ko.yml +52 -52
  84. data/web/locales/lt.yml +66 -66
  85. data/web/locales/nb.yml +61 -61
  86. data/web/locales/nl.yml +52 -52
  87. data/web/locales/pl.yml +45 -45
  88. data/web/locales/pt-br.yml +78 -69
  89. data/web/locales/pt.yml +51 -51
  90. data/web/locales/ru.yml +67 -66
  91. data/web/locales/sv.yml +53 -53
  92. data/web/locales/ta.yml +60 -60
  93. data/web/locales/tr.yml +100 -0
  94. data/web/locales/uk.yml +85 -61
  95. data/web/locales/ur.yml +64 -64
  96. data/web/locales/vi.yml +67 -67
  97. data/web/locales/zh-cn.yml +42 -16
  98. data/web/locales/zh-tw.yml +41 -8
  99. data/web/views/_footer.erb +17 -2
  100. data/web/views/_job_info.erb +18 -2
  101. data/web/views/_metrics_period_select.erb +12 -0
  102. data/web/views/_nav.erb +1 -1
  103. data/web/views/_paging.erb +2 -0
  104. data/web/views/_poll_link.erb +1 -1
  105. data/web/views/_summary.erb +7 -7
  106. data/web/views/busy.erb +49 -33
  107. data/web/views/dashboard.erb +28 -6
  108. data/web/views/filtering.erb +6 -0
  109. data/web/views/layout.erb +6 -6
  110. data/web/views/metrics.erb +90 -0
  111. data/web/views/metrics_for_job.erb +59 -0
  112. data/web/views/morgue.erb +5 -9
  113. data/web/views/queue.erb +15 -15
  114. data/web/views/queues.erb +9 -3
  115. data/web/views/retries.erb +5 -9
  116. data/web/views/scheduled.erb +12 -13
  117. metadata +61 -26
  118. data/lib/sidekiq/.DS_Store +0 -0
  119. data/lib/sidekiq/delay.rb +0 -43
  120. data/lib/sidekiq/extensions/action_mailer.rb +0 -48
  121. data/lib/sidekiq/extensions/active_record.rb +0 -43
  122. data/lib/sidekiq/extensions/class_methods.rb +0 -43
  123. data/lib/sidekiq/extensions/generic_proxy.rb +0 -33
  124. data/lib/sidekiq/worker.rb +0 -367
  125. /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)
@@ -6,8 +6,51 @@ require "yaml"
6
6
  require "cgi"
7
7
 
8
8
  module Sidekiq
9
- # This is not a public API
9
+ # These methods are available to pages within the Web UI and UI extensions.
10
+ # They are not public APIs for applications to use.
10
11
  module WebHelpers
12
+ def style_tag(location, **kwargs)
13
+ global = location.match?(/:\/\//)
14
+ location = root_path + location if !global && !location.start_with?(root_path)
15
+ attrs = {
16
+ type: "text/css",
17
+ media: "screen",
18
+ rel: "stylesheet",
19
+ nonce: csp_nonce,
20
+ href: location
21
+ }
22
+ html_tag(:link, attrs.merge(kwargs))
23
+ end
24
+
25
+ def script_tag(location, **kwargs)
26
+ global = location.match?(/:\/\//)
27
+ location = root_path + location if !global && !location.start_with?(root_path)
28
+ attrs = {
29
+ type: "text/javascript",
30
+ nonce: csp_nonce,
31
+ src: location
32
+ }
33
+ html_tag(:script, attrs.merge(kwargs)) {}
34
+ end
35
+
36
+ # NB: keys and values are not escaped; do not allow user input
37
+ # in the attributes
38
+ private def html_tag(tagname, attrs)
39
+ s = +"<#{tagname}"
40
+ attrs.each_pair do |k, v|
41
+ next unless v
42
+ s << " #{k}=\"#{v}\""
43
+ end
44
+ if block_given?
45
+ s << ">"
46
+ yield s
47
+ s << "</#{tagname}>"
48
+ else
49
+ s << " />"
50
+ end
51
+ s
52
+ end
53
+
11
54
  def strings(lang)
12
55
  @strings ||= {}
13
56
 
@@ -15,12 +58,16 @@ module Sidekiq
15
58
  # so extensions can be localized
16
59
  @strings[lang] ||= settings.locales.each_with_object({}) do |path, global|
17
60
  find_locale_files(lang).each do |file|
18
- strs = YAML.load(File.open(file))
61
+ strs = YAML.safe_load(File.read(file))
19
62
  global.merge!(strs[lang])
20
63
  end
21
64
  end
22
65
  end
23
66
 
67
+ def to_json(x)
68
+ Sidekiq.dump_json(x)
69
+ end
70
+
24
71
  def singularize(str, count)
25
72
  if count == 1 && str.respond_to?(:singularize) # rails
26
73
  str.singularize
@@ -42,15 +89,36 @@ module Sidekiq
42
89
  end
43
90
 
44
91
  def available_locales
45
- @available_locales ||= locale_files.map { |path| File.basename(path, ".yml") }.uniq
92
+ @available_locales ||= Set.new(locale_files.map { |path| File.basename(path, ".yml") })
46
93
  end
47
94
 
48
95
  def find_locale_files(lang)
49
96
  locale_files.select { |file| file =~ /\/#{lang}\.yml$/ }
50
97
  end
51
98
 
52
- # This is a hook for a Sidekiq Pro feature. Please don't touch.
53
- def filtering(*)
99
+ def search(jobset, substr)
100
+ resultset = jobset.scan(substr).to_a
101
+ @current_page = 1
102
+ @count = @total_size = resultset.size
103
+ resultset
104
+ end
105
+
106
+ def filtering(which)
107
+ erb(:filtering, locals: {which: which})
108
+ end
109
+
110
+ def filter_link(jid, within = "retries")
111
+ if within.nil?
112
+ ::Rack::Utils.escape_html(jid)
113
+ else
114
+ "<a href='#{root_path}filter/#{within}?substr=#{jid}'>#{::Rack::Utils.escape_html(jid)}</a>"
115
+ end
116
+ end
117
+
118
+ def display_tags(job, within = "retries")
119
+ job.tags.map { |tag|
120
+ "<span class='label label-info jobtag'>#{filter_link(tag, within)}</span>"
121
+ }.join(" ")
54
122
  end
55
123
 
56
124
  # This view helper provide ability display you html code in
@@ -96,7 +164,10 @@ module Sidekiq
96
164
  #
97
165
  # Inspiration taken from https://github.com/iain/http_accept_language/blob/master/lib/http_accept_language/parser.rb
98
166
  def locale
99
- @locale ||= begin
167
+ # session[:locale] is set via the locale selector from the footer
168
+ @locale ||= if (l = session&.fetch(:locale, nil)) && available_locales.include?(l)
169
+ l
170
+ else
100
171
  matched_locale = user_preferred_languages.map { |preferred|
101
172
  preferred_language = preferred.split("-", 2).first
102
173
 
@@ -111,14 +182,7 @@ module Sidekiq
111
182
  end
112
183
  end
113
184
 
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
185
+ # sidekiq/sidekiq#3243
122
186
  def unfiltered?
123
187
  yield unless env["PATH_INFO"].start_with?("/filter/")
124
188
  end
@@ -137,7 +201,7 @@ module Sidekiq
137
201
  end
138
202
 
139
203
  def sort_direction_label
140
- params[:direction] == "asc" ? "&uarr;" : "&darr;"
204
+ (params[:direction] == "asc") ? "&uarr;" : "&darr;"
141
205
  end
142
206
 
143
207
  def workset
@@ -148,22 +212,39 @@ module Sidekiq
148
212
  @processes ||= Sidekiq::ProcessSet.new
149
213
  end
150
214
 
215
+ # Sorts processes by hostname following the natural sort order
216
+ def sorted_processes
217
+ @sorted_processes ||= begin
218
+ return processes unless processes.all? { |p| p["hostname"] }
219
+
220
+ processes.to_a.sort_by do |process|
221
+ # Kudos to `shurikk` on StackOverflow
222
+ # https://stackoverflow.com/a/15170063/575547
223
+ process["hostname"].split(/(\d+)/).map { |a| /\d+/.match?(a) ? a.to_i : a }
224
+ end
225
+ end
226
+ end
227
+
228
+ def busy_weights(capsule_weights)
229
+ # backwards compat with 7.0.0, remove in 7.1
230
+ cw = [capsule_weights].flatten
231
+ cw.map { |hash|
232
+ hash.map { |name, weight| (weight > 0) ? +name << ": " << weight.to_s : name }.join(", ")
233
+ }.join("; ")
234
+ end
235
+
151
236
  def stats
152
237
  @stats ||= Sidekiq::Stats.new
153
238
  end
154
239
 
155
- def redis_connection
240
+ def redis_url
156
241
  Sidekiq.redis do |conn|
157
- conn.connection[:id]
242
+ conn.config.server_url
158
243
  end
159
244
  end
160
245
 
161
- def namespace
162
- @ns ||= Sidekiq.redis { |conn| conn.respond_to?(:namespace) ? conn.namespace : nil }
163
- end
164
-
165
246
  def redis_info
166
- Sidekiq.redis_info
247
+ Sidekiq.default_configuration.redis_info
167
248
  end
168
249
 
169
250
  def root_path
@@ -175,7 +256,7 @@ module Sidekiq
175
256
  end
176
257
 
177
258
  def current_status
178
- workset.size == 0 ? "idle" : "active"
259
+ (workset.size == 0) ? "idle" : "active"
179
260
  end
180
261
 
181
262
  def relative_time(time)
@@ -208,7 +289,7 @@ module Sidekiq
208
289
  end
209
290
 
210
291
  def truncate(text, truncate_after_chars = 2000)
211
- truncate_after_chars && text.size > truncate_after_chars ? "#{text[0..truncate_after_chars]}..." : text
292
+ (truncate_after_chars && text.size > truncate_after_chars) ? "#{text[0..truncate_after_chars]}..." : text
212
293
  end
213
294
 
214
295
  def display_args(args, truncate_after_chars = 2000)
@@ -228,6 +309,10 @@ module Sidekiq
228
309
  "<input type='hidden' name='authenticity_token' value='#{env[:csrf_token]}'/>"
229
310
  end
230
311
 
312
+ def csp_nonce
313
+ env[:csp_nonce]
314
+ end
315
+
231
316
  def to_display(arg)
232
317
  arg.inspect
233
318
  rescue
@@ -261,27 +346,17 @@ module Sidekiq
261
346
  elsif rss_kb < 10_000_000
262
347
  "#{number_with_delimiter((rss_kb / 1024.0).to_i)} MB"
263
348
  else
264
- "#{number_with_delimiter((rss_kb / (1024.0 * 1024.0)).round(1))} GB"
349
+ "#{number_with_delimiter((rss_kb / (1024.0 * 1024.0)), precision: 1)} GB"
265
350
  end
266
351
  end
267
352
 
268
- def number_with_delimiter(number)
269
- return "" if number.nil?
270
-
271
- begin
272
- Float(number)
273
- rescue ArgumentError, TypeError
274
- return number
275
- end
276
-
277
- options = {delimiter: ",", separator: "."}
278
- parts = number.to_s.to_str.split(".")
279
- parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
280
- parts.join(options[:separator])
353
+ def number_with_delimiter(number, options = {})
354
+ precision = options[:precision] || 0
355
+ %(<span data-nwp="#{precision}">#{number.round(precision)}</span>)
281
356
  end
282
357
 
283
358
  def h(text)
284
- ::Rack::Utils.escape_html(text)
359
+ ::Rack::Utils.escape_html(text.to_s)
285
360
  rescue ArgumentError => e
286
361
  raise unless e.message.eql?("invalid byte sequence in UTF-8")
287
362
  text.encode!("UTF-16", "UTF-8", invalid: :replace, replace: "").encode!("UTF-8", "UTF-16")
@@ -301,7 +376,7 @@ module Sidekiq
301
376
  end
302
377
 
303
378
  def environment_title_prefix
304
- environment = Sidekiq[:environment] || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
379
+ environment = Sidekiq.default_configuration[:environment] || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
305
380
 
306
381
  "[#{environment.upcase}] " unless environment == "production"
307
382
  end
@@ -314,11 +389,9 @@ module Sidekiq
314
389
  Time.now.utc.strftime("%H:%M:%S UTC")
315
390
  end
316
391
 
317
- def redis_connection_and_namespace
318
- @redis_connection_and_namespace ||= begin
319
- namespace_suffix = namespace.nil? ? "" : "##{namespace}"
320
- "#{redis_connection}#{namespace_suffix}"
321
- end
392
+ def pollable?
393
+ # there's no point to refreshing the metrics pages every N seconds
394
+ !(current_path == "" || current_path.index("metrics"))
322
395
  end
323
396
 
324
397
  def retry_or_delete_or_kill(job, params)
@@ -39,10 +39,13 @@ module Sidekiq
39
39
  route(DELETE, path, &block)
40
40
  end
41
41
 
42
- def route(method, path, &block)
42
+ def route(*methods, path, &block)
43
43
  @routes ||= {GET => [], POST => [], PUT => [], PATCH => [], DELETE => [], HEAD => []}
44
44
 
45
- @routes[method] << WebRoute.new(method, path, block)
45
+ methods.each do |method|
46
+ method = method.to_s.upcase
47
+ @routes[method] << WebRoute.new(method, path, block)
48
+ end
46
49
  end
47
50
 
48
51
  def match(env)
data/lib/sidekiq/web.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "erb"
4
+ require "securerandom"
4
5
 
5
6
  require "sidekiq"
6
7
  require "sidekiq/api"
@@ -30,9 +31,24 @@ module Sidekiq
30
31
  "Queues" => "queues",
31
32
  "Retries" => "retries",
32
33
  "Scheduled" => "scheduled",
33
- "Dead" => "morgue"
34
+ "Dead" => "morgue",
35
+ "Metrics" => "metrics"
34
36
  }
35
37
 
38
+ if Gem::Version.new(Rack::RELEASE) < Gem::Version.new("3")
39
+ CONTENT_LANGUAGE = "Content-Language"
40
+ CONTENT_SECURITY_POLICY = "Content-Security-Policy"
41
+ LOCATION = "Location"
42
+ X_CASCADE = "X-Cascade"
43
+ X_CONTENT_TYPE_OPTIONS = "X-Content-Type-Options"
44
+ else
45
+ CONTENT_LANGUAGE = "content-language"
46
+ CONTENT_SECURITY_POLICY = "content-security-policy"
47
+ LOCATION = "location"
48
+ X_CASCADE = "x-cascade"
49
+ X_CONTENT_TYPE_OPTIONS = "x-content-type-options"
50
+ end
51
+
36
52
  class << self
37
53
  def settings
38
54
  self
@@ -47,6 +63,10 @@ module Sidekiq
47
63
  end
48
64
  alias_method :tabs, :custom_tabs
49
65
 
66
+ def custom_job_info_rows
67
+ @custom_job_info_rows ||= []
68
+ end
69
+
50
70
  def locales
51
71
  @locales ||= LOCALES
52
72
  end
@@ -75,14 +95,6 @@ module Sidekiq
75
95
  send(:"#{attribute}=", value)
76
96
  end
77
97
 
78
- def sessions=(val)
79
- puts "WARNING: Sidekiq::Web.sessions= is no longer relevant and will be removed in Sidekiq 7.0. #{caller(1..1).first}"
80
- end
81
-
82
- def session_secret=(val)
83
- puts "WARNING: Sidekiq::Web.session_secret= is no longer relevant and will be removed in Sidekiq 7.0. #{caller(1..1).first}"
84
- end
85
-
86
98
  attr_accessor :app_url, :redis_pool
87
99
  attr_writer :locales, :views
88
100
  end
@@ -105,6 +117,7 @@ module Sidekiq
105
117
  end
106
118
 
107
119
  def call(env)
120
+ env[:csp_nonce] = SecureRandom.base64(16)
108
121
  app.call(env)
109
122
  end
110
123
 
@@ -129,11 +142,50 @@ module Sidekiq
129
142
  send(:"#{attribute}=", value)
130
143
  end
131
144
 
132
- def sessions=(val)
133
- puts "Sidekiq::Web#sessions= is no longer relevant and will be removed in Sidekiq 7.0. #{caller[2..2].first}"
134
- end
145
+ # Register a class as a Sidekiq Web UI extension. The class should
146
+ # provide one or more tabs which map to an index route. Options:
147
+ #
148
+ # @param extension [Class] Class which contains the HTTP actions, required
149
+ # @param name [String] the name of the extension, used to namespace assets
150
+ # @param tab [String | Array] labels(s) of the UI tabs
151
+ # @param index [String | Array] index route(s) for each tab
152
+ # @param root_dir [String] directory location to find assets, locales and views, typically `web/` within the gemfile
153
+ # @param asset_paths [Array] one or more directories under {root}/assets/{name} to be publicly served, e.g. ["js", "css", "img"]
154
+ # @param cache_for [Integer] amount of time to cache assets, default one day
155
+ #
156
+ # TODO name, tab and index will be mandatory in 8.0
157
+ #
158
+ # Web extensions will have a root `web/` directory with `locales/`, `assets/`
159
+ # and `views/` subdirectories.
160
+ def self.register(extension, name: nil, tab: nil, index: nil, root_dir: nil, cache_for: 86400, asset_paths: nil)
161
+ tab = Array(tab)
162
+ index = Array(index)
163
+ tab.zip(index).each do |tab, index|
164
+ tabs[tab] = index
165
+ end
166
+ if root_dir
167
+ locdir = File.join(root_dir, "locales")
168
+ locales << locdir if File.directory?(locdir)
169
+
170
+ if asset_paths && name
171
+ # if you have {root}/assets/{name}/js/scripts.js
172
+ # and {root}/assets/{name}/css/styles.css
173
+ # you would pass in:
174
+ # asset_paths: ["js", "css"]
175
+ # See script_tag and style_tag in web/helpers.rb
176
+ assdir = File.join(root_dir, "assets")
177
+ assurls = Array(asset_paths).map { |x| "/#{name}/#{x}" }
178
+ assetprops = {
179
+ urls: assurls,
180
+ root: assdir,
181
+ cascade: true
182
+ }
183
+ assetprops[:header_rules] = [[:all, {Rack::CACHE_CONTROL => "private, max-age=#{cache_for.to_i}"}]] if cache_for
184
+ middlewares << [[Rack::Static, assetprops], nil]
185
+ end
186
+ end
135
187
 
136
- def self.register(extension)
188
+ yield self if block_given?
137
189
  extension.registered(WebApplication)
138
190
  end
139
191
 
@@ -144,7 +196,7 @@ module Sidekiq
144
196
  m = middlewares
145
197
 
146
198
  rules = []
147
- rules = [[:all, {"Cache-Control" => "public, max-age=86400"}]] unless ENV["SIDEKIQ_WEB_TESTING"]
199
+ rules = [[:all, {Rack::CACHE_CONTROL => "private, max-age=86400"}]] unless ENV["SIDEKIQ_WEB_TESTING"]
148
200
 
149
201
  ::Rack::Builder.new do
150
202
  use Rack::Static, urls: ["/stylesheets", "/images", "/javascripts"],
@@ -161,7 +213,7 @@ module Sidekiq
161
213
  Sidekiq::WebApplication.helpers WebHelpers
162
214
  Sidekiq::WebApplication.helpers Sidekiq::Paginator
163
215
 
164
- Sidekiq::WebAction.class_eval <<-RUBY, __FILE__, __LINE__ + 1
216
+ Sidekiq::WebAction.class_eval <<-RUBY, Web::LAYOUT, -1 # standard:disable Style/EvalWithLocation
165
217
  def _render
166
218
  #{ERB.new(File.read(Web::LAYOUT)).src}
167
219
  end
@@ -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