sidekiq 6.0.7 → 6.5.0

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 (107) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +209 -2
  3. data/LICENSE +3 -3
  4. data/README.md +11 -10
  5. data/bin/sidekiq +8 -3
  6. data/bin/sidekiqload +70 -66
  7. data/bin/sidekiqmon +1 -1
  8. data/lib/generators/sidekiq/job_generator.rb +57 -0
  9. data/lib/generators/sidekiq/templates/{worker.rb.erb → job.rb.erb} +2 -2
  10. data/lib/generators/sidekiq/templates/{worker_spec.rb.erb → job_spec.rb.erb} +1 -1
  11. data/lib/generators/sidekiq/templates/{worker_test.rb.erb → job_test.rb.erb} +1 -1
  12. data/lib/sidekiq/api.rb +180 -123
  13. data/lib/sidekiq/cli.rb +80 -45
  14. data/lib/sidekiq/client.rb +52 -71
  15. data/lib/sidekiq/{util.rb → component.rb} +11 -14
  16. data/lib/sidekiq/delay.rb +2 -0
  17. data/lib/sidekiq/extensions/action_mailer.rb +3 -2
  18. data/lib/sidekiq/extensions/active_record.rb +4 -3
  19. data/lib/sidekiq/extensions/class_methods.rb +5 -4
  20. data/lib/sidekiq/extensions/generic_proxy.rb +4 -2
  21. data/lib/sidekiq/fetch.rb +41 -30
  22. data/lib/sidekiq/job.rb +13 -0
  23. data/lib/sidekiq/job_logger.rb +16 -28
  24. data/lib/sidekiq/job_retry.rb +36 -36
  25. data/lib/sidekiq/job_util.rb +71 -0
  26. data/lib/sidekiq/launcher.rb +123 -63
  27. data/lib/sidekiq/logger.rb +11 -20
  28. data/lib/sidekiq/manager.rb +35 -34
  29. data/lib/sidekiq/middleware/chain.rb +28 -17
  30. data/lib/sidekiq/middleware/current_attributes.rb +61 -0
  31. data/lib/sidekiq/middleware/i18n.rb +6 -4
  32. data/lib/sidekiq/middleware/modules.rb +19 -0
  33. data/lib/sidekiq/monitor.rb +1 -1
  34. data/lib/sidekiq/paginator.rb +8 -8
  35. data/lib/sidekiq/processor.rb +41 -41
  36. data/lib/sidekiq/rails.rb +38 -22
  37. data/lib/sidekiq/redis_client_adapter.rb +154 -0
  38. data/lib/sidekiq/redis_connection.rb +87 -53
  39. data/lib/sidekiq/ring_buffer.rb +29 -0
  40. data/lib/sidekiq/scheduled.rb +60 -24
  41. data/lib/sidekiq/sd_notify.rb +1 -1
  42. data/lib/sidekiq/testing/inline.rb +4 -4
  43. data/lib/sidekiq/testing.rb +39 -40
  44. data/lib/sidekiq/transaction_aware_client.rb +45 -0
  45. data/lib/sidekiq/version.rb +1 -1
  46. data/lib/sidekiq/web/action.rb +2 -2
  47. data/lib/sidekiq/web/application.rb +21 -12
  48. data/lib/sidekiq/web/csrf_protection.rb +180 -0
  49. data/lib/sidekiq/web/helpers.rb +40 -34
  50. data/lib/sidekiq/web/router.rb +5 -2
  51. data/lib/sidekiq/web.rb +36 -72
  52. data/lib/sidekiq/worker.rb +136 -16
  53. data/lib/sidekiq.rb +107 -30
  54. data/sidekiq.gemspec +11 -4
  55. data/web/assets/images/apple-touch-icon.png +0 -0
  56. data/web/assets/javascripts/application.js +113 -65
  57. data/web/assets/javascripts/dashboard.js +51 -51
  58. data/web/assets/stylesheets/application-dark.css +64 -43
  59. data/web/assets/stylesheets/application-rtl.css +0 -4
  60. data/web/assets/stylesheets/application.css +42 -239
  61. data/web/locales/ar.yml +8 -2
  62. data/web/locales/en.yml +4 -1
  63. data/web/locales/es.yml +18 -2
  64. data/web/locales/fr.yml +8 -1
  65. data/web/locales/ja.yml +3 -0
  66. data/web/locales/lt.yml +1 -1
  67. data/web/locales/pl.yml +4 -4
  68. data/web/locales/pt-br.yml +27 -9
  69. data/web/locales/ru.yml +4 -0
  70. data/web/views/_footer.erb +1 -1
  71. data/web/views/_job_info.erb +1 -1
  72. data/web/views/_poll_link.erb +2 -5
  73. data/web/views/_summary.erb +7 -7
  74. data/web/views/busy.erb +51 -20
  75. data/web/views/dashboard.erb +22 -14
  76. data/web/views/dead.erb +1 -1
  77. data/web/views/layout.erb +2 -1
  78. data/web/views/morgue.erb +6 -6
  79. data/web/views/queue.erb +11 -11
  80. data/web/views/queues.erb +4 -4
  81. data/web/views/retries.erb +7 -7
  82. data/web/views/retry.erb +1 -1
  83. data/web/views/scheduled.erb +1 -1
  84. metadata +29 -51
  85. data/.circleci/config.yml +0 -60
  86. data/.github/contributing.md +0 -32
  87. data/.github/issue_template.md +0 -11
  88. data/.gitignore +0 -13
  89. data/.standard.yml +0 -20
  90. data/3.0-Upgrade.md +0 -70
  91. data/4.0-Upgrade.md +0 -53
  92. data/5.0-Upgrade.md +0 -56
  93. data/6.0-Upgrade.md +0 -72
  94. data/COMM-LICENSE +0 -97
  95. data/Ent-2.0-Upgrade.md +0 -37
  96. data/Ent-Changes.md +0 -256
  97. data/Gemfile +0 -24
  98. data/Gemfile.lock +0 -208
  99. data/Pro-2.0-Upgrade.md +0 -138
  100. data/Pro-3.0-Upgrade.md +0 -44
  101. data/Pro-4.0-Upgrade.md +0 -35
  102. data/Pro-5.0-Upgrade.md +0 -25
  103. data/Pro-Changes.md +0 -782
  104. data/Rakefile +0 -10
  105. data/code_of_conduct.md +0 -50
  106. data/lib/generators/sidekiq/worker_generator.rb +0 -57
  107. data/lib/sidekiq/exception_handler.rb +0 -27
@@ -9,6 +9,7 @@ module Sidekiq
9
9
  #
10
10
  # class HardWorker
11
11
  # include Sidekiq::Worker
12
+ # sidekiq_options queue: 'critical', retry: 5
12
13
  #
13
14
  # def perform(*args)
14
15
  # # do some work
@@ -20,6 +21,26 @@ module Sidekiq
20
21
  # HardWorker.perform_async(1, 2, 3)
21
22
  #
22
23
  # Note that perform_async is a class method, perform is an instance method.
24
+ #
25
+ # Sidekiq::Worker also includes several APIs to provide compatibility with
26
+ # ActiveJob.
27
+ #
28
+ # class SomeWorker
29
+ # include Sidekiq::Worker
30
+ # queue_as :critical
31
+ #
32
+ # def perform(...)
33
+ # end
34
+ # end
35
+ #
36
+ # SomeWorker.set(wait_until: 1.hour).perform_async(123)
37
+ #
38
+ # Note that arguments passed to the job must still obey Sidekiq's
39
+ # best practice for simple, JSON-native data types. Sidekiq will not
40
+ # implement ActiveJob's more complex argument serialization. For
41
+ # this reason, we don't implement `perform_later` as our call semantics
42
+ # are very different.
43
+ #
23
44
  module Worker
24
45
  ##
25
46
  # The Options module is extracted so we can include it in ActiveJob::Base
@@ -61,7 +82,7 @@ module Sidekiq
61
82
  end
62
83
 
63
84
  def get_sidekiq_options # :nodoc:
64
- self.sidekiq_options_hash ||= Sidekiq.default_worker_options
85
+ self.sidekiq_options_hash ||= Sidekiq.default_job_options
65
86
  end
66
87
 
67
88
  def sidekiq_class_attribute(*attrs)
@@ -150,33 +171,97 @@ module Sidekiq
150
171
  # SomeWorker.set(queue: 'foo').perform_async(....)
151
172
  #
152
173
  class Setter
174
+ include Sidekiq::JobUtil
175
+
153
176
  def initialize(klass, opts)
154
177
  @klass = klass
155
- @opts = opts
178
+ # NB: the internal hash always has stringified keys
179
+ @opts = opts.transform_keys(&:to_s)
180
+
181
+ # ActiveJob compatibility
182
+ interval = @opts.delete("wait_until") || @opts.delete("wait")
183
+ at(interval) if interval
156
184
  end
157
185
 
158
186
  def set(options)
159
- @opts.merge!(options)
187
+ hash = options.transform_keys(&:to_s)
188
+ interval = hash.delete("wait_until") || @opts.delete("wait")
189
+ @opts.merge!(hash)
190
+ at(interval) if interval
160
191
  self
161
192
  end
162
193
 
163
194
  def perform_async(*args)
164
- @klass.client_push(@opts.merge("args" => args, "class" => @klass))
195
+ if @opts["sync"] == true
196
+ perform_inline(*args)
197
+ else
198
+ @klass.client_push(@opts.merge("args" => args, "class" => @klass))
199
+ end
200
+ end
201
+
202
+ # Explicit inline execution of a job. Returns nil if the job did not
203
+ # execute, true otherwise.
204
+ def perform_inline(*args)
205
+ raw = @opts.merge("args" => args, "class" => @klass)
206
+
207
+ # validate and normalize payload
208
+ item = normalize_item(raw)
209
+ queue = item["queue"]
210
+
211
+ # run client-side middleware
212
+ result = Sidekiq.client_middleware.invoke(item["class"], item, queue, Sidekiq.redis_pool) do
213
+ item
214
+ end
215
+ return nil unless result
216
+
217
+ # round-trip the payload via JSON
218
+ msg = Sidekiq.load_json(Sidekiq.dump_json(item))
219
+
220
+ # prepare the job instance
221
+ klass = msg["class"].constantize
222
+ job = klass.new
223
+ job.jid = msg["jid"]
224
+ job.bid = msg["bid"] if job.respond_to?(:bid)
225
+
226
+ # run the job through server-side middleware
227
+ result = Sidekiq.server_middleware.invoke(job, msg, msg["queue"]) do
228
+ # perform it
229
+ job.perform(*msg["args"])
230
+ true
231
+ end
232
+ return nil unless result
233
+ # jobs do not return a result. they should store any
234
+ # modified state.
235
+ true
236
+ end
237
+ alias_method :perform_sync, :perform_inline
238
+
239
+ def perform_bulk(args, batch_size: 1_000)
240
+ client = @klass.build_client
241
+ result = args.each_slice(batch_size).flat_map do |slice|
242
+ client.push_bulk(@opts.merge("class" => @klass, "args" => slice))
243
+ end
244
+
245
+ result.is_a?(Enumerator::Lazy) ? result.force : result
165
246
  end
166
247
 
167
248
  # +interval+ must be a timestamp, numeric or something that acts
168
249
  # numeric (like an activesupport time interval).
169
250
  def perform_in(interval, *args)
251
+ at(interval).perform_async(*args)
252
+ end
253
+ alias_method :perform_at, :perform_in
254
+
255
+ private
256
+
257
+ def at(interval)
170
258
  int = interval.to_f
171
259
  now = Time.now.to_f
172
260
  ts = (int < 1_000_000_000 ? now + int : int)
173
-
174
- payload = @opts.merge("class" => @klass, "args" => args)
175
261
  # Optimization to enqueue something now that is scheduled to go out now or in the past
176
- payload["at"] = ts if ts > now
177
- @klass.client_push(payload)
262
+ @opts["at"] = ts if ts > now
263
+ self
178
264
  end
179
- alias_method :perform_at, :perform_in
180
265
  end
181
266
 
182
267
  module ClassMethods
@@ -192,12 +277,46 @@ module Sidekiq
192
277
  raise ArgumentError, "Do not call .delay_until on a Sidekiq::Worker class, call .perform_at"
193
278
  end
194
279
 
280
+ def queue_as(q)
281
+ sidekiq_options("queue" => q.to_s)
282
+ end
283
+
195
284
  def set(options)
196
285
  Setter.new(self, options)
197
286
  end
198
287
 
199
288
  def perform_async(*args)
200
- client_push("class" => self, "args" => args)
289
+ Setter.new(self, {}).perform_async(*args)
290
+ end
291
+
292
+ # Inline execution of job's perform method after passing through Sidekiq.client_middleware and Sidekiq.server_middleware
293
+ def perform_inline(*args)
294
+ Setter.new(self, {}).perform_inline(*args)
295
+ end
296
+ alias_method :perform_sync, :perform_inline
297
+
298
+ ##
299
+ # Push a large number of jobs to Redis, while limiting the batch of
300
+ # each job payload to 1,000. This method helps cut down on the number
301
+ # of round trips to Redis, which can increase the performance of enqueueing
302
+ # large numbers of jobs.
303
+ #
304
+ # +items+ must be an Array of Arrays.
305
+ #
306
+ # For finer-grained control, use `Sidekiq::Client.push_bulk` directly.
307
+ #
308
+ # Example (3 Redis round trips):
309
+ #
310
+ # SomeWorker.perform_async(1)
311
+ # SomeWorker.perform_async(2)
312
+ # SomeWorker.perform_async(3)
313
+ #
314
+ # Would instead become (1 Redis round trip):
315
+ #
316
+ # SomeWorker.perform_bulk([[1], [2], [3]])
317
+ #
318
+ def perform_bulk(*args, **kwargs)
319
+ Setter.new(self, {}).perform_bulk(*args, **kwargs)
201
320
  end
202
321
 
203
322
  # +interval+ must be a timestamp, numeric or something that acts
@@ -234,13 +353,14 @@ module Sidekiq
234
353
  end
235
354
 
236
355
  def client_push(item) # :nodoc:
237
- pool = Thread.current[:sidekiq_via_pool] || get_sidekiq_options["pool"] || Sidekiq.redis_pool
238
- # stringify
239
- item.keys.each do |key|
240
- item[key.to_s] = item.delete(key)
241
- end
356
+ raise ArgumentError, "Job payloads should contain no Symbols: #{item}" if item.any? { |k, v| k.is_a?(::Symbol) }
357
+ build_client.push(item)
358
+ end
242
359
 
243
- Sidekiq::Client.new(pool).push(item)
360
+ def build_client # :nodoc:
361
+ pool = Thread.current[:sidekiq_via_pool] || get_sidekiq_options["pool"] || Sidekiq.redis_pool
362
+ client_class = get_sidekiq_options["client_class"] || Sidekiq::Client
363
+ client_class.new(pool)
244
364
  end
245
365
  end
246
366
  end
data/lib/sidekiq.rb CHANGED
@@ -5,7 +5,9 @@ fail "Sidekiq #{Sidekiq::VERSION} does not support Ruby versions below 2.5.0." i
5
5
 
6
6
  require "sidekiq/logger"
7
7
  require "sidekiq/client"
8
+ require "sidekiq/transaction_aware_client"
8
9
  require "sidekiq/worker"
10
+ require "sidekiq/job"
9
11
  require "sidekiq/redis_connection"
10
12
  require "sidekiq/delay"
11
13
 
@@ -20,10 +22,12 @@ module Sidekiq
20
22
  labels: [],
21
23
  concurrency: 10,
22
24
  require: ".",
25
+ strict: true,
23
26
  environment: nil,
24
27
  timeout: 25,
25
28
  poll_interval_average: nil,
26
29
  average_scheduled_poll_interval: 5,
30
+ on_complex_arguments: :warn,
27
31
  error_handlers: [],
28
32
  death_handlers: [],
29
33
  lifecycle_events: {
@@ -37,11 +41,6 @@ module Sidekiq
37
41
  reloader: proc { |&block| block.call }
38
42
  }
39
43
 
40
- DEFAULT_WORKER_OPTIONS = {
41
- "retry" => true,
42
- "queue" => "default"
43
- }
44
-
45
44
  FAKE_INFO = {
46
45
  "redis_version" => "9.9.9",
47
46
  "uptime_in_days" => "9999",
@@ -54,19 +53,79 @@ module Sidekiq
54
53
  puts "Calm down, yo."
55
54
  end
56
55
 
56
+ # config.concurrency = 5
57
+ def self.concurrency=(val)
58
+ self[:concurrency] = Integer(val)
59
+ end
60
+
61
+ # config.queues = %w( high default low ) # strict
62
+ # config.queues = %w( high,3 default,2 low,1 ) # weighted
63
+ # config.queues = %w( feature1,1 feature2,1 feature3,1 ) # random
64
+ #
65
+ # With weighted priority, queue will be checked first (weight / total) of the time.
66
+ # high will be checked first (3/6) or 50% of the time.
67
+ # I'd recommend setting weights between 1-10. Weights in the hundreds or thousands
68
+ # are ridiculous and unnecessarily expensive. You can get random queue ordering
69
+ # by explicitly setting all weights to 1.
70
+ def self.queues=(val)
71
+ self[:queues] = Array(val).each_with_object([]) do |qstr, memo|
72
+ name, weight = qstr.split(",")
73
+ self[:strict] = false if weight.to_i > 0
74
+ [weight.to_i, 1].max.times do
75
+ memo << name
76
+ end
77
+ end
78
+ end
79
+
80
+ ### Private APIs
81
+ def self.default_error_handler(ex, ctx)
82
+ logger.warn(dump_json(ctx)) unless ctx.empty?
83
+ logger.warn("#{ex.class.name}: #{ex.message}")
84
+ logger.warn(ex.backtrace.join("\n")) unless ex.backtrace.nil?
85
+ end
86
+
87
+ @config = DEFAULTS.dup
57
88
  def self.options
58
- @options ||= DEFAULTS.dup
89
+ logger.warn "`config.options[:key] = value` is deprecated, use `config[:key] = value`: #{caller(1..2)}"
90
+ @config
59
91
  end
60
92
 
61
93
  def self.options=(opts)
62
- @options = opts
94
+ logger.warn "config.options = hash` is deprecated, use `config.merge!(hash)`: #{caller(1..2)}"
95
+ @config = opts
96
+ end
97
+
98
+ def self.[](key)
99
+ @config[key]
100
+ end
101
+
102
+ def self.[]=(key, val)
103
+ @config[key] = val
63
104
  end
64
105
 
106
+ def self.merge!(hash)
107
+ @config.merge!(hash)
108
+ end
109
+
110
+ def self.fetch(*args, &block)
111
+ @config.fetch(*args, &block)
112
+ end
113
+
114
+ def self.handle_exception(ex, ctx = {})
115
+ self[:error_handlers].each do |handler|
116
+ handler.call(ex, ctx)
117
+ rescue => ex
118
+ logger.error "!!! ERROR HANDLER THREW AN ERROR !!!"
119
+ logger.error ex
120
+ logger.error ex.backtrace.join("\n") unless ex.backtrace.nil?
121
+ end
122
+ end
123
+ ###
124
+
65
125
  ##
66
126
  # Configuration for Sidekiq server, use like:
67
127
  #
68
128
  # Sidekiq.configure_server do |config|
69
- # config.redis = { :namespace => 'myapp', :size => 25, :url => 'redis://myhost:8877/0' }
70
129
  # config.server_middleware do |chain|
71
130
  # chain.add MyServerHook
72
131
  # end
@@ -79,7 +138,7 @@ module Sidekiq
79
138
  # Configuration for Sidekiq client, use like:
80
139
  #
81
140
  # Sidekiq.configure_client do |config|
82
- # config.redis = { :namespace => 'myapp', :size => 1, :url => 'redis://myhost:8877/0' }
141
+ # config.redis = { size: 1, url: 'redis://myhost:8877/0' }
83
142
  # end
84
143
  def self.configure_client
85
144
  yield self unless server?
@@ -95,10 +154,13 @@ module Sidekiq
95
154
  retryable = true
96
155
  begin
97
156
  yield conn
98
- rescue Redis::CommandError => ex
157
+ rescue RedisConnection.adapter::BaseError => ex
99
158
  # 2550 Failover can cause the server to become a replica, need
100
159
  # to disconnect and reopen the socket to get back to the primary.
101
- if retryable && ex.message =~ /READONLY/
160
+ # 4495 Use the same logic if we have a "Not enough replicas" error from the primary
161
+ # 4985 Use the same logic when a blocking command is force-unblocked
162
+ # The same retry logic is also used in client.rb
163
+ if retryable && ex.message =~ /READONLY|NOREPLICAS|UNBLOCKED/
102
164
  conn.disconnect!
103
165
  retryable = false
104
166
  retry
@@ -117,7 +179,7 @@ module Sidekiq
117
179
  else
118
180
  conn.info
119
181
  end
120
- rescue Redis::CommandError => ex
182
+ rescue RedisConnection.adapter::CommandError => ex
121
183
  # 2850 return fake version when INFO command has (probably) been renamed
122
184
  raise unless /unknown command/.match?(ex.message)
123
185
  FAKE_INFO
@@ -125,19 +187,19 @@ module Sidekiq
125
187
  end
126
188
 
127
189
  def self.redis_pool
128
- @redis ||= Sidekiq::RedisConnection.create
190
+ @redis ||= RedisConnection.create
129
191
  end
130
192
 
131
193
  def self.redis=(hash)
132
194
  @redis = if hash.is_a?(ConnectionPool)
133
195
  hash
134
196
  else
135
- Sidekiq::RedisConnection.create(hash)
197
+ RedisConnection.create(hash)
136
198
  end
137
199
  end
138
200
 
139
201
  def self.client_middleware
140
- @client_chain ||= Middleware::Chain.new
202
+ @client_chain ||= Middleware::Chain.new(self)
141
203
  yield @client_chain if block_given?
142
204
  @client_chain
143
205
  end
@@ -149,16 +211,23 @@ module Sidekiq
149
211
  end
150
212
 
151
213
  def self.default_server_middleware
152
- Middleware::Chain.new
214
+ Middleware::Chain.new(self)
153
215
  end
154
216
 
155
- def self.default_worker_options=(hash)
156
- # stringify
157
- @default_worker_options = default_worker_options.merge(hash.transform_keys(&:to_s))
217
+ def self.default_worker_options=(hash) # deprecated
218
+ @default_job_options = default_job_options.merge(hash.transform_keys(&:to_s))
158
219
  end
159
220
 
160
- def self.default_worker_options
161
- defined?(@default_worker_options) ? @default_worker_options : DEFAULT_WORKER_OPTIONS
221
+ def self.default_job_options=(hash)
222
+ @default_job_options = default_job_options.merge(hash.transform_keys(&:to_s))
223
+ end
224
+
225
+ def self.default_worker_options # deprecated
226
+ @default_job_options ||= {"retry" => true, "queue" => "default"}
227
+ end
228
+
229
+ def self.default_job_options
230
+ @default_job_options ||= {"retry" => true, "queue" => "default"}
162
231
  end
163
232
 
164
233
  ##
@@ -171,7 +240,7 @@ module Sidekiq
171
240
  # end
172
241
  # end
173
242
  def self.death_handlers
174
- options[:death_handlers]
243
+ self[:death_handlers]
175
244
  end
176
245
 
177
246
  def self.load_json(string)
@@ -196,7 +265,7 @@ module Sidekiq
196
265
  end
197
266
 
198
267
  def self.logger
199
- @logger ||= Sidekiq::Logger.new(STDOUT, level: Logger::INFO)
268
+ @logger ||= Sidekiq::Logger.new($stdout, level: :info)
200
269
  end
201
270
 
202
271
  def self.logger=(logger)
@@ -214,13 +283,17 @@ module Sidekiq
214
283
  defined?(Sidekiq::Pro)
215
284
  end
216
285
 
286
+ def self.ent?
287
+ defined?(Sidekiq::Enterprise)
288
+ end
289
+
217
290
  # How frequently Redis should be checked by a random Sidekiq process for
218
291
  # scheduled and retriable jobs. Each individual process will take turns by
219
292
  # waiting some multiple of this value.
220
293
  #
221
294
  # See sidekiq/scheduled.rb for an in-depth explanation of this value
222
295
  def self.average_scheduled_poll_interval=(interval)
223
- options[:average_scheduled_poll_interval] = interval
296
+ self[:average_scheduled_poll_interval] = interval
224
297
  end
225
298
 
226
299
  # Register a proc to handle any error which occurs within the Sidekiq process.
@@ -231,7 +304,7 @@ module Sidekiq
231
304
  #
232
305
  # The default error handler logs errors to Sidekiq.logger.
233
306
  def self.error_handlers
234
- options[:error_handlers]
307
+ self[:error_handlers]
235
308
  end
236
309
 
237
310
  # Register a block to run at a point in the Sidekiq lifecycle.
@@ -244,16 +317,20 @@ module Sidekiq
244
317
  # end
245
318
  def self.on(event, &block)
246
319
  raise ArgumentError, "Symbols only please: #{event}" unless event.is_a?(Symbol)
247
- raise ArgumentError, "Invalid event name: #{event}" unless options[:lifecycle_events].key?(event)
248
- options[:lifecycle_events][event] << block
320
+ raise ArgumentError, "Invalid event name: #{event}" unless self[:lifecycle_events].key?(event)
321
+ self[:lifecycle_events][event] << block
322
+ end
323
+
324
+ def self.strict_args!(mode = :raise)
325
+ self[:on_complex_arguments] = mode
249
326
  end
250
327
 
251
- # We are shutting down Sidekiq but what about workers that
328
+ # We are shutting down Sidekiq but what about threads that
252
329
  # are working on some long job? This error is
253
- # raised in workers that have not finished within the hard
330
+ # raised in jobs that have not finished within the hard
254
331
  # timeout limit. This is needed to rollback db transactions,
255
332
  # otherwise Ruby's Thread#kill will commit. See #377.
256
- # DO NOT RESCUE THIS ERROR IN YOUR WORKERS
333
+ # DO NOT RESCUE THIS ERROR IN YOUR JOBS
257
334
  class Shutdown < Interrupt; end
258
335
  end
259
336
 
data/sidekiq.gemspec CHANGED
@@ -5,17 +5,24 @@ Gem::Specification.new do |gem|
5
5
  gem.email = ["mperham@gmail.com"]
6
6
  gem.summary = "Simple, efficient background processing for Ruby"
7
7
  gem.description = "Simple, efficient background processing for Ruby."
8
- gem.homepage = "http://sidekiq.org"
8
+ gem.homepage = "https://sidekiq.org"
9
9
  gem.license = "LGPL-3.0"
10
10
 
11
11
  gem.executables = ["sidekiq", "sidekiqmon"]
12
- gem.files = `git ls-files | grep -Ev '^(test|myapp|examples)'`.split("\n")
12
+ gem.files = ["sidekiq.gemspec", "README.md", "Changes.md", "LICENSE"] + `git ls-files | grep -E '^(bin|lib|web)'`.split("\n")
13
13
  gem.name = "sidekiq"
14
14
  gem.version = Sidekiq::VERSION
15
15
  gem.required_ruby_version = ">= 2.5.0"
16
16
 
17
- gem.add_dependency "redis", ">= 4.1.0"
17
+ gem.metadata = {
18
+ "homepage_uri" => "https://sidekiq.org",
19
+ "bug_tracker_uri" => "https://github.com/mperham/sidekiq/issues",
20
+ "documentation_uri" => "https://github.com/mperham/sidekiq/wiki",
21
+ "changelog_uri" => "https://github.com/mperham/sidekiq/blob/main/Changes.md",
22
+ "source_code_uri" => "https://github.com/mperham/sidekiq"
23
+ }
24
+
25
+ gem.add_dependency "redis", ">= 4.2.0"
18
26
  gem.add_dependency "connection_pool", ">= 2.2.2"
19
27
  gem.add_dependency "rack", "~> 2.0"
20
- gem.add_dependency "rack-protection", ">= 2.0.0"
21
28
  end