sidekiq 6.4.2 → 6.5.1

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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 70d899b76bdd764a2ec7e5f23b6d056494b58897daaf49db672daad3e0f60237
4
- data.tar.gz: daae0430ecaf8eb7f172c70e628581c20a17e1a7cb1a58170b9082fc3dde1ea2
3
+ metadata.gz: 1afbc6a1a0b14403e9148e746c08e0a2b24e634fca05288982c96719675607de
4
+ data.tar.gz: 3ff3f8df76b565f42030462eb8d09b673b89751dcd6a0b7c41a255789960d321
5
5
  SHA512:
6
- metadata.gz: 930a0feb7ff47473eb995f8ba695468498afecb311c25296c93042ecfa00cd2bf48e19efd5ba775b4895c065705a344043e0c0e5d7b4115c2dceb1ec7cf341f9
7
- data.tar.gz: 14ab645609e7c9f3fa954432097cd46d6e9e74e5bddc9ed1541697d13f3399add407ffb5af23c89c82651793c97e2c54b8fd4f845ca20287ce6bf033fd9caed2
6
+ metadata.gz: e8a68611735322d98cc517f1d03ef02394497f8eb505e0db496909cac1f6b7f0179f38ce1966546f717115395102c78fdad9ae0fd947360307b9288dcc22b369
7
+ data.tar.gz: 163e41dfb153a4e2ec50d407bde08cb8a395909807053f24478a73af1a6a9858b5aec92cbf618d4d066560a2b7bedaa2f88b48f823609e2d78f21320270cb97e
data/Changes.md CHANGED
@@ -2,6 +2,30 @@
2
2
 
3
3
  [Sidekiq Changes](https://github.com/mperham/sidekiq/blob/main/Changes.md) | [Sidekiq Pro Changes](https://github.com/mperham/sidekiq/blob/main/Pro-Changes.md) | [Sidekiq Enterprise Changes](https://github.com/mperham/sidekiq/blob/main/Ent-Changes.md)
4
4
 
5
+ 6.5.1
6
+ ----------
7
+
8
+ - Fix `push_bulk` breakage [#5387]
9
+
10
+ 6.5.0
11
+ ---------
12
+
13
+ - Substantial refactoring of Sidekiq server internals, part of a larger effort
14
+ to reduce Sidekiq's internal usage of global methods and data, see [docs/global_to_local.md](docs/global_to_local.md) and [docs/middleware.md](docs/middleware.md).
15
+ - **Add beta support for the `redis-client` gem**. This will become the default Redis driver in Sidekiq 7.0. [#5298]
16
+ Read more: https://github.com/mperham/sidekiq/wiki/Using-redis-client
17
+ - **Add beta support for DB transaction-aware client** [#5291]
18
+ Add this line to your initializer and any jobs created during a transaction
19
+ will only be pushed to Redis **after the transaction commits**. You will need to add the
20
+ `after_commit_everywhere` gem to your Gemfile.
21
+ ```ruby
22
+ Sidekiq.transactional_push!
23
+ ```
24
+ This feature does not have a lot of production usage yet; please try it out and let us
25
+ know if you have any issues. It will be fully supported in Sidekiq 7.0 or removed if it
26
+ proves problematic.
27
+ - Fix regression with middleware arguments [#5312]
28
+
5
29
  6.4.2
6
30
  ---------
7
31
 
data/bin/sidekiqload CHANGED
@@ -11,6 +11,10 @@ Bundler.require(:default, :load_test)
11
11
  require_relative "../lib/sidekiq/cli"
12
12
  require_relative "../lib/sidekiq/launcher"
13
13
 
14
+ if ENV["SIDEKIQ_REDIS_CLIENT"]
15
+ Sidekiq::RedisConnection.adapter = :redis_client
16
+ end
17
+
14
18
  Sidekiq.configure_server do |config|
15
19
  config.options[:concurrency] = 10
16
20
  config.redis = {db: 13, port: 6380}
@@ -118,15 +122,23 @@ Monitoring = Thread.new do
118
122
  end
119
123
  end
120
124
 
125
+ def with_latency(latency, &block)
126
+ Sidekiq.logger.error "Simulating #{latency}ms of latency between Sidekiq and redis"
127
+ if latency > 0
128
+ Toxiproxy[:redis].downstream(:latency, latency: latency).apply(&block)
129
+ else
130
+ yield
131
+ end
132
+ end
133
+
121
134
  begin
122
135
  # RubyProf::exclude_threads = [ Monitoring ]
123
136
  # RubyProf.start
124
137
  events = Sidekiq.options[:lifecycle_events][:startup]
125
138
  events.each(&:call)
126
139
  events.clear
127
-
128
- Sidekiq.logger.error "Simulating 1ms of latency between Sidekiq and redis"
129
- Toxiproxy[:redis].downstream(:latency, latency: 1).apply do
140
+
141
+ with_latency(Integer(ENV.fetch("LATENCY", "1"))) do
130
142
  launcher = Sidekiq::Launcher.new(Sidekiq.options)
131
143
  launcher.run
132
144
 
Binary file
data/lib/sidekiq/api.rb CHANGED
@@ -191,7 +191,7 @@ module Sidekiq
191
191
  stat_hash[dates[idx]] = value ? value.to_i : 0
192
192
  end
193
193
  end
194
- rescue Redis::CommandError
194
+ rescue RedisConnection.adapter::CommandError
195
195
  # mget will trigger a CROSSSLOT error when run against a Cluster
196
196
  # TODO Someone want to add Cluster support?
197
197
  end
@@ -217,24 +217,30 @@ module Sidekiq
217
217
  include Enumerable
218
218
 
219
219
  ##
220
- # Return all known queues within Redis.
220
+ # Fetch all known queues within Redis.
221
221
  #
222
+ # @return [Array<Sidekiq::Queue>]
222
223
  def self.all
223
224
  Sidekiq.redis { |c| c.sscan_each("queues").to_a }.sort.map { |q| Sidekiq::Queue.new(q) }
224
225
  end
225
226
 
226
227
  attr_reader :name
227
228
 
229
+ # @param name [String] the name of the queue
228
230
  def initialize(name = "default")
229
231
  @name = name.to_s
230
232
  @rname = "queue:#{name}"
231
233
  end
232
234
 
235
+ # The current size of the queue within Redis.
236
+ # This value is real-time and can change between calls.
237
+ #
238
+ # @return [Integer] the size
233
239
  def size
234
240
  Sidekiq.redis { |con| con.llen(@rname) }
235
241
  end
236
242
 
237
- # Sidekiq Pro overrides this
243
+ # @return [Boolean] if the queue is currently paused
238
244
  def paused?
239
245
  false
240
246
  end
@@ -243,7 +249,7 @@ module Sidekiq
243
249
  # Calculates this queue's latency, the difference in seconds since the oldest
244
250
  # job in the queue was enqueued.
245
251
  #
246
- # @return Float
252
+ # @return [Float] in seconds
247
253
  def latency
248
254
  entry = Sidekiq.redis { |conn|
249
255
  conn.lrange(@rname, -1, -1)
@@ -279,12 +285,17 @@ module Sidekiq
279
285
  ##
280
286
  # Find the job with the given JID within this queue.
281
287
  #
282
- # This is a slow, inefficient operation. Do not use under
288
+ # This is a *slow, inefficient* operation. Do not use under
283
289
  # normal conditions.
290
+ #
291
+ # @param jid [String] the job_id to look for
292
+ # @return [Sidekiq::JobRecord]
293
+ # @return [nil] if not found
284
294
  def find_job(jid)
285
295
  detect { |j| j.jid == jid }
286
296
  end
287
297
 
298
+ # delete all jobs within this queue
288
299
  def clear
289
300
  Sidekiq.redis do |conn|
290
301
  conn.multi do |transaction|
@@ -294,6 +305,10 @@ module Sidekiq
294
305
  end
295
306
  end
296
307
  alias_method :💣, :clear
308
+
309
+ def as_json(options = nil) # :nodoc:
310
+ {name: name} # 5336
311
+ end
297
312
  end
298
313
 
299
314
  ##
@@ -306,15 +321,16 @@ module Sidekiq
306
321
  class JobRecord
307
322
  attr_reader :item
308
323
  attr_reader :value
324
+ attr_reader :queue
309
325
 
310
- def initialize(item, queue_name = nil)
326
+ def initialize(item, queue_name = nil) # :nodoc:
311
327
  @args = nil
312
328
  @value = item
313
329
  @item = item.is_a?(Hash) ? item : parse(item)
314
330
  @queue = queue_name || @item["queue"]
315
331
  end
316
332
 
317
- def parse(item)
333
+ def parse(item) # :nodoc:
318
334
  Sidekiq.load_json(item)
319
335
  rescue JSON::ParserError
320
336
  # If the job payload in Redis is invalid JSON, we'll load
@@ -412,15 +428,12 @@ module Sidekiq
412
428
  end
413
429
  end
414
430
 
415
- attr_reader :queue
416
-
417
431
  def latency
418
432
  now = Time.now.to_f
419
433
  now - (@item["enqueued_at"] || @item["created_at"] || now)
420
434
  end
421
435
 
422
- ##
423
- # Remove this job from the queue.
436
+ # Remove this job from the queue
424
437
  def delete
425
438
  count = Sidekiq.redis { |conn|
426
439
  conn.lrem("queue:#{@queue}", 1, @value)
@@ -428,6 +441,7 @@ module Sidekiq
428
441
  count != 0
429
442
  end
430
443
 
444
+ # Access arbitrary attributes within the job hash
431
445
  def [](name)
432
446
  # nil will happen if the JSON fails to parse.
433
447
  # We don't guarantee Sidekiq will work with bad job JSON but we should
@@ -442,7 +456,8 @@ module Sidekiq
442
456
  rescue => ex
443
457
  # #1761 in dev mode, it's possible to have jobs enqueued which haven't been loaded into
444
458
  # memory yet so the YAML can't be loaded.
445
- Sidekiq.logger.warn "Unable to load YAML: #{ex.message}" unless Sidekiq.options[:environment] == "development"
459
+ # TODO is this still necessary? Zeitwerk reloader should handle?
460
+ Sidekiq.logger.warn "Unable to load YAML: #{ex.message}" unless Sidekiq.config[:environment] == "development"
446
461
  default
447
462
  end
448
463
 
@@ -464,13 +479,15 @@ module Sidekiq
464
479
  end
465
480
  end
466
481
 
482
+ # Represents a job within a Redis sorted set where the score
483
+ # represents a timestamp for the job.
467
484
  class SortedEntry < JobRecord
468
485
  attr_reader :score
469
486
  attr_reader :parent
470
487
 
471
- def initialize(parent, score, item)
488
+ def initialize(parent, score, item) # :nodoc:
472
489
  super(item)
473
- @score = score
490
+ @score = Float(score)
474
491
  @parent = parent
475
492
  end
476
493
 
@@ -486,12 +503,17 @@ module Sidekiq
486
503
  end
487
504
  end
488
505
 
506
+ # Change the scheduled time for this job.
507
+ #
508
+ # @param [Time] the new timestamp when this job will be enqueued.
489
509
  def reschedule(at)
490
510
  Sidekiq.redis do |conn|
491
511
  conn.zincrby(@parent.name, at.to_f - @score, Sidekiq.dump_json(@item))
492
512
  end
493
513
  end
494
514
 
515
+ # Enqueue this job from the scheduled or dead set so it will
516
+ # be executed at some point in the near future.
495
517
  def add_to_queue
496
518
  remove_job do |message|
497
519
  msg = Sidekiq.load_json(message)
@@ -499,6 +521,8 @@ module Sidekiq
499
521
  end
500
522
  end
501
523
 
524
+ # enqueue this job from the retry set so it will be executed
525
+ # at some point in the near future.
502
526
  def retry
503
527
  remove_job do |message|
504
528
  msg = Sidekiq.load_json(message)
@@ -507,8 +531,7 @@ module Sidekiq
507
531
  end
508
532
  end
509
533
 
510
- ##
511
- # Place job in the dead set
534
+ # Move this job from its current set into the Dead set.
512
535
  def kill
513
536
  remove_job do |message|
514
537
  DeadSet.new.kill(message)
@@ -587,6 +610,10 @@ module Sidekiq
587
610
  end
588
611
  end
589
612
  alias_method :💣, :clear
613
+
614
+ def as_json(options = nil) # :nodoc:
615
+ {name: name} # 5336
616
+ end
590
617
  end
591
618
 
592
619
  class JobSet < SortedSet
@@ -606,7 +633,7 @@ module Sidekiq
606
633
  range_start = page * page_size + offset_size
607
634
  range_end = range_start + page_size - 1
608
635
  elements = Sidekiq.redis { |conn|
609
- conn.zrange name, range_start, range_end, with_scores: true
636
+ conn.zrange name, range_start, range_end, withscores: true
610
637
  }
611
638
  break if elements.empty?
612
639
  page -= 1
@@ -629,7 +656,7 @@ module Sidekiq
629
656
  end
630
657
 
631
658
  elements = Sidekiq.redis { |conn|
632
- conn.zrangebyscore(name, begin_score, end_score, with_scores: true)
659
+ conn.zrangebyscore(name, begin_score, end_score, withscores: true)
633
660
  }
634
661
 
635
662
  elements.each_with_object([]) do |element, result|
@@ -758,11 +785,11 @@ module Sidekiq
758
785
  end
759
786
 
760
787
  def self.max_jobs
761
- Sidekiq.options[:dead_max_jobs]
788
+ Sidekiq[:dead_max_jobs]
762
789
  end
763
790
 
764
791
  def self.timeout
765
- Sidekiq.options[:dead_timeout_in_seconds]
792
+ Sidekiq[:dead_timeout_in_seconds]
766
793
  end
767
794
  end
768
795
 
data/lib/sidekiq/cli.rb CHANGED
@@ -9,18 +9,23 @@ require "erb"
9
9
  require "fileutils"
10
10
 
11
11
  require "sidekiq"
12
+ require "sidekiq/component"
12
13
  require "sidekiq/launcher"
13
- require "sidekiq/util"
14
14
 
15
- module Sidekiq
15
+ module Sidekiq # :nodoc:
16
16
  class CLI
17
- include Util
17
+ include Sidekiq::Component
18
18
  include Singleton unless $TESTING
19
19
 
20
20
  attr_accessor :launcher
21
21
  attr_accessor :environment
22
+ attr_accessor :config
22
23
 
23
24
  def parse(args = ARGV.dup)
25
+ @config = Sidekiq
26
+ @config[:error_handlers].clear
27
+ @config[:error_handlers] << @config.method(:default_error_handler)
28
+
24
29
  setup_options(args)
25
30
  initialize_logger
26
31
  validate!
@@ -36,7 +41,7 @@ module Sidekiq
36
41
  def run(boot_app: true)
37
42
  boot_application if boot_app
38
43
 
39
- if environment == "development" && $stdout.tty? && Sidekiq.log_formatter.is_a?(Sidekiq::Logger::Formatters::Pretty)
44
+ if environment == "development" && $stdout.tty? && @config.log_formatter.is_a?(Sidekiq::Logger::Formatters::Pretty)
40
45
  print_banner
41
46
  end
42
47
  logger.info "Booted Rails #{::Rails.version} application in #{environment} environment" if rails_app?
@@ -67,7 +72,7 @@ module Sidekiq
67
72
 
68
73
  # touch the connection pool so it is created before we
69
74
  # fire startup and start multithreading.
70
- info = Sidekiq.redis_info
75
+ info = @config.redis_info
71
76
  ver = info["redis_version"]
72
77
  raise "You are connecting to Redis v#{ver}, Sidekiq requires Redis v4.0.0 or greater" if ver < "4"
73
78
 
@@ -85,22 +90,22 @@ module Sidekiq
85
90
 
86
91
  # Since the user can pass us a connection pool explicitly in the initializer, we
87
92
  # need to verify the size is large enough or else Sidekiq's performance is dramatically slowed.
88
- cursize = Sidekiq.redis_pool.size
89
- needed = Sidekiq.options[:concurrency] + 2
93
+ cursize = @config.redis_pool.size
94
+ needed = @config[:concurrency] + 2
90
95
  raise "Your pool of #{cursize} Redis connections is too small, please increase the size to at least #{needed}" if cursize < needed
91
96
 
92
97
  # cache process identity
93
- Sidekiq.options[:identity] = identity
98
+ @config[:identity] = identity
94
99
 
95
100
  # Touch middleware so it isn't lazy loaded by multiple threads, #3043
96
- Sidekiq.server_middleware
101
+ @config.server_middleware
97
102
 
98
103
  # Before this point, the process is initializing with just the main thread.
99
104
  # Starting here the process will now have multiple threads running.
100
105
  fire_event(:startup, reverse: false, reraise: true)
101
106
 
102
- logger.debug { "Client Middleware: #{Sidekiq.client_middleware.map(&:klass).join(", ")}" }
103
- logger.debug { "Server Middleware: #{Sidekiq.server_middleware.map(&:klass).join(", ")}" }
107
+ logger.debug { "Client Middleware: #{@config.client_middleware.map(&:klass).join(", ")}" }
108
+ logger.debug { "Server Middleware: #{@config.server_middleware.map(&:klass).join(", ")}" }
104
109
 
105
110
  launch(self_read)
106
111
  end
@@ -110,7 +115,7 @@ module Sidekiq
110
115
  logger.info "Starting processing, hit Ctrl-C to stop"
111
116
  end
112
117
 
113
- @launcher = Sidekiq::Launcher.new(options)
118
+ @launcher = Sidekiq::Launcher.new(@config)
114
119
 
115
120
  begin
116
121
  launcher.run
@@ -173,25 +178,25 @@ module Sidekiq
173
178
  # Heroku sends TERM and then waits 30 seconds for process to exit.
174
179
  "TERM" => ->(cli) { raise Interrupt },
175
180
  "TSTP" => ->(cli) {
176
- Sidekiq.logger.info "Received TSTP, no longer accepting new work"
181
+ cli.logger.info "Received TSTP, no longer accepting new work"
177
182
  cli.launcher.quiet
178
183
  },
179
184
  "TTIN" => ->(cli) {
180
185
  Thread.list.each do |thread|
181
- Sidekiq.logger.warn "Thread TID-#{(thread.object_id ^ ::Process.pid).to_s(36)} #{thread.name}"
186
+ cli.logger.warn "Thread TID-#{(thread.object_id ^ ::Process.pid).to_s(36)} #{thread.name}"
182
187
  if thread.backtrace
183
- Sidekiq.logger.warn thread.backtrace.join("\n")
188
+ cli.logger.warn thread.backtrace.join("\n")
184
189
  else
185
- Sidekiq.logger.warn "<no backtrace available>"
190
+ cli.logger.warn "<no backtrace available>"
186
191
  end
187
192
  end
188
193
  }
189
194
  }
190
- UNHANDLED_SIGNAL_HANDLER = ->(cli) { Sidekiq.logger.info "No signal handler registered, ignoring" }
195
+ UNHANDLED_SIGNAL_HANDLER = ->(cli) { cli.logger.info "No signal handler registered, ignoring" }
191
196
  SIGNAL_HANDLERS.default = UNHANDLED_SIGNAL_HANDLER
192
197
 
193
198
  def handle_signal(sig)
194
- Sidekiq.logger.debug "Got #{sig} signal"
199
+ logger.debug "Got #{sig} signal"
195
200
  SIGNAL_HANDLERS[sig].call(self)
196
201
  end
197
202
 
@@ -237,7 +242,7 @@ module Sidekiq
237
242
  config_dir = if File.directory?(opts[:require].to_s)
238
243
  File.join(opts[:require], "config")
239
244
  else
240
- File.join(options[:require], "config")
245
+ File.join(@config[:require], "config")
241
246
  end
242
247
 
243
248
  %w[sidekiq.yml sidekiq.yml.erb].each do |config_file|
@@ -254,27 +259,23 @@ module Sidekiq
254
259
  opts[:concurrency] = Integer(ENV["RAILS_MAX_THREADS"]) if opts[:concurrency].nil? && ENV["RAILS_MAX_THREADS"]
255
260
 
256
261
  # merge with defaults
257
- options.merge!(opts)
258
- end
259
-
260
- def options
261
- Sidekiq.options
262
+ @config.merge!(opts)
262
263
  end
263
264
 
264
265
  def boot_application
265
266
  ENV["RACK_ENV"] = ENV["RAILS_ENV"] = environment
266
267
 
267
- if File.directory?(options[:require])
268
+ if File.directory?(@config[:require])
268
269
  require "rails"
269
270
  if ::Rails::VERSION::MAJOR < 5
270
271
  raise "Sidekiq no longer supports this version of Rails"
271
272
  else
272
273
  require "sidekiq/rails"
273
- require File.expand_path("#{options[:require]}/config/environment.rb")
274
+ require File.expand_path("#{@config[:require]}/config/environment.rb")
274
275
  end
275
- options[:tag] ||= default_tag
276
+ @config[:tag] ||= default_tag
276
277
  else
277
- require options[:require]
278
+ require @config[:require]
278
279
  end
279
280
  end
280
281
 
@@ -291,8 +292,8 @@ module Sidekiq
291
292
  end
292
293
 
293
294
  def validate!
294
- if !File.exist?(options[:require]) ||
295
- (File.directory?(options[:require]) && !File.exist?("#{options[:require]}/config/application.rb"))
295
+ if !File.exist?(@config[:require]) ||
296
+ (File.directory?(@config[:require]) && !File.exist?("#{@config[:require]}/config/application.rb"))
296
297
  logger.info "=================================================================="
297
298
  logger.info " Please point Sidekiq to a Rails application or a Ruby file "
298
299
  logger.info " to load your job classes with -r [DIR|FILE]."
@@ -302,7 +303,7 @@ module Sidekiq
302
303
  end
303
304
 
304
305
  [:concurrency, :timeout].each do |opt|
305
- raise ArgumentError, "#{opt}: #{options[opt]} is not a valid value" if options.key?(opt) && options[opt].to_i <= 0
306
+ raise ArgumentError, "#{opt}: #{@config[opt]} is not a valid value" if @config[opt].to_i <= 0
306
307
  end
307
308
  end
308
309
 
@@ -376,7 +377,7 @@ module Sidekiq
376
377
  end
377
378
 
378
379
  def initialize_logger
379
- Sidekiq.logger.level = ::Logger::DEBUG if options[:verbose]
380
+ @config.logger.level = ::Logger::DEBUG if @config[:verbose]
380
381
  end
381
382
 
382
383
  def parse_config(path)
@@ -71,7 +71,7 @@ module Sidekiq
71
71
  #
72
72
  def push(item)
73
73
  normed = normalize_item(item)
74
- payload = middleware.invoke(normed["class"], normed, normed["queue"], @redis_pool) do
74
+ payload = middleware.invoke(item["class"], normed, normed["queue"], @redis_pool) do
75
75
  normed
76
76
  end
77
77
  if payload
@@ -110,7 +110,7 @@ module Sidekiq
110
110
  payloads = args.map.with_index { |job_args, index|
111
111
  copy = normed.merge("args" => job_args, "jid" => SecureRandom.hex(12))
112
112
  copy["at"] = (at.is_a?(Array) ? at[index] : at) if at
113
- result = middleware.invoke(copy["class"], copy, copy["queue"], @redis_pool) do
113
+ result = middleware.invoke(items["class"], copy, copy["queue"], @redis_pool) do
114
114
  verify_json(copy)
115
115
  copy
116
116
  end
@@ -201,7 +201,7 @@ module Sidekiq
201
201
  conn.pipelined do |pipeline|
202
202
  atomic_push(pipeline, payloads)
203
203
  end
204
- rescue Redis::BaseError => ex
204
+ rescue RedisConnection.adapter::BaseError => ex
205
205
  # 2550 Failover can cause the server to become a replica, need
206
206
  # to disconnect and reopen the socket to get back to the primary.
207
207
  # 4495 Use the same logic if we have a "Not enough replicas" error from the primary
@@ -220,7 +220,7 @@ module Sidekiq
220
220
 
221
221
  def atomic_push(conn, payloads)
222
222
  if payloads.first.key?("at")
223
- conn.zadd("schedule", payloads.map { |hash|
223
+ conn.zadd("schedule", payloads.flat_map { |hash|
224
224
  at = hash.delete("at").to_s
225
225
  [at, Sidekiq.dump_json(hash)]
226
226
  })
@@ -0,0 +1,64 @@
1
+ module Sidekiq
2
+ ##
3
+ # Sidekiq::Component assumes a config instance is available at @config
4
+ module Component # :nodoc:
5
+ attr_reader :config
6
+
7
+ def watchdog(last_words)
8
+ yield
9
+ rescue Exception => ex
10
+ handle_exception(ex, {context: last_words})
11
+ raise ex
12
+ end
13
+
14
+ def safe_thread(name, &block)
15
+ Thread.new do
16
+ Thread.current.name = name
17
+ watchdog(name, &block)
18
+ end
19
+ end
20
+
21
+ def logger
22
+ config.logger
23
+ end
24
+
25
+ def redis(&block)
26
+ config.redis(&block)
27
+ end
28
+
29
+ def tid
30
+ Thread.current["sidekiq_tid"] ||= (Thread.current.object_id ^ ::Process.pid).to_s(36)
31
+ end
32
+
33
+ def hostname
34
+ ENV["DYNO"] || Socket.gethostname
35
+ end
36
+
37
+ def process_nonce
38
+ @@process_nonce ||= SecureRandom.hex(6)
39
+ end
40
+
41
+ def identity
42
+ @@identity ||= "#{hostname}:#{::Process.pid}:#{process_nonce}"
43
+ end
44
+
45
+ def handle_exception(ex, ctx = {})
46
+ config.handle_exception(ex, ctx)
47
+ end
48
+
49
+ def fire_event(event, options = {})
50
+ reverse = options[:reverse]
51
+ reraise = options[:reraise]
52
+
53
+ arr = config[:lifecycle_events][event]
54
+ arr.reverse! if reverse
55
+ arr.each do |block|
56
+ block.call
57
+ rescue => ex
58
+ handle_exception(ex, {context: "Exception during Sidekiq lifecycle event.", event: event})
59
+ raise ex if reraise
60
+ end
61
+ arr.clear # once we've fired an event, we never fire it again
62
+ end
63
+ end
64
+ end
data/lib/sidekiq/delay.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Sidekiq
3
+ module Sidekiq # :nodoc:
4
4
  module Extensions
5
5
  def self.enable_delay!
6
6
  warn "Sidekiq's Delayed Extensions will be removed in Sidekiq 7.0", uplevel: 1
data/lib/sidekiq/fetch.rb CHANGED
@@ -1,14 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "sidekiq"
4
+ require "sidekiq/component"
4
5
 
5
- module Sidekiq
6
+ module Sidekiq # :nodoc:
6
7
  class BasicFetch
8
+ include Sidekiq::Component
7
9
  # We want the fetch operation to timeout every few seconds so the thread
8
10
  # can check if the process is shutting down.
9
11
  TIMEOUT = 2
10
12
 
11
- UnitOfWork = Struct.new(:queue, :job) {
13
+ UnitOfWork = Struct.new(:queue, :job, :config) {
12
14
  def acknowledge
13
15
  # nothing to do
14
16
  end
@@ -18,17 +20,17 @@ module Sidekiq
18
20
  end
19
21
 
20
22
  def requeue
21
- Sidekiq.redis do |conn|
23
+ config.redis do |conn|
22
24
  conn.rpush(queue, job)
23
25
  end
24
26
  end
25
27
  }
26
28
 
27
- def initialize(options)
28
- raise ArgumentError, "missing queue list" unless options[:queues]
29
- @options = options
30
- @strictly_ordered_queues = !!@options[:strict]
31
- @queues = @options[:queues].map { |q| "queue:#{q}" }
29
+ def initialize(config)
30
+ raise ArgumentError, "missing queue list" unless config[:queues]
31
+ @config = config
32
+ @strictly_ordered_queues = !!@config[:strict]
33
+ @queues = @config[:queues].map { |q| "queue:#{q}" }
32
34
  if @strictly_ordered_queues
33
35
  @queues.uniq!
34
36
  @queues << TIMEOUT
@@ -44,30 +46,30 @@ module Sidekiq
44
46
  return nil
45
47
  end
46
48
 
47
- work = Sidekiq.redis { |conn| conn.brpop(*qs) }
48
- UnitOfWork.new(*work) if work
49
+ queue, job = redis { |conn| conn.brpop(*qs) }
50
+ UnitOfWork.new(queue, job, config) if queue
49
51
  end
50
52
 
51
53
  def bulk_requeue(inprogress, options)
52
54
  return if inprogress.empty?
53
55
 
54
- Sidekiq.logger.debug { "Re-queueing terminated jobs" }
56
+ logger.debug { "Re-queueing terminated jobs" }
55
57
  jobs_to_requeue = {}
56
58
  inprogress.each do |unit_of_work|
57
59
  jobs_to_requeue[unit_of_work.queue] ||= []
58
60
  jobs_to_requeue[unit_of_work.queue] << unit_of_work.job
59
61
  end
60
62
 
61
- Sidekiq.redis do |conn|
63
+ redis do |conn|
62
64
  conn.pipelined do |pipeline|
63
65
  jobs_to_requeue.each do |queue, jobs|
64
66
  pipeline.rpush(queue, jobs)
65
67
  end
66
68
  end
67
69
  end
68
- Sidekiq.logger.info("Pushed #{inprogress.size} jobs back to Redis")
70
+ logger.info("Pushed #{inprogress.size} jobs back to Redis")
69
71
  rescue => ex
70
- Sidekiq.logger.warn("Failed to requeue #{inprogress.size} jobs: #{ex.message}")
72
+ logger.warn("Failed to requeue #{inprogress.size} jobs: #{ex.message}")
71
73
  end
72
74
 
73
75
  # Creating the Redis#brpop command takes into account any