sidekiq 6.4.2 → 6.5.2

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +35 -0
  3. data/bin/sidekiqload +15 -3
  4. data/lib/sidekiq/api.rb +160 -32
  5. data/lib/sidekiq/cli.rb +34 -32
  6. data/lib/sidekiq/client.rb +4 -4
  7. data/lib/sidekiq/component.rb +65 -0
  8. data/lib/sidekiq/delay.rb +1 -1
  9. data/lib/sidekiq/fetch.rb +16 -14
  10. data/lib/sidekiq/job_retry.rb +50 -34
  11. data/lib/sidekiq/job_util.rb +7 -3
  12. data/lib/sidekiq/launcher.rb +22 -19
  13. data/lib/sidekiq/logger.rb +1 -1
  14. data/lib/sidekiq/manager.rb +23 -20
  15. data/lib/sidekiq/metrics/deploy.rb +47 -0
  16. data/lib/sidekiq/metrics/query.rb +124 -0
  17. data/lib/sidekiq/metrics/shared.rb +94 -0
  18. data/lib/sidekiq/metrics/tracking.rb +134 -0
  19. data/lib/sidekiq/middleware/chain.rb +82 -38
  20. data/lib/sidekiq/middleware/current_attributes.rb +10 -4
  21. data/lib/sidekiq/middleware/i18n.rb +2 -0
  22. data/lib/sidekiq/middleware/modules.rb +21 -0
  23. data/lib/sidekiq/paginator.rb +2 -2
  24. data/lib/sidekiq/processor.rb +13 -13
  25. data/lib/sidekiq/rails.rb +5 -5
  26. data/lib/sidekiq/redis_client_adapter.rb +154 -0
  27. data/lib/sidekiq/redis_connection.rb +80 -47
  28. data/lib/sidekiq/ring_buffer.rb +29 -0
  29. data/lib/sidekiq/scheduled.rb +11 -10
  30. data/lib/sidekiq/testing.rb +1 -1
  31. data/lib/sidekiq/transaction_aware_client.rb +45 -0
  32. data/lib/sidekiq/version.rb +1 -1
  33. data/lib/sidekiq/web/application.rb +13 -0
  34. data/lib/sidekiq/web/helpers.rb +25 -2
  35. data/lib/sidekiq/web.rb +4 -0
  36. data/lib/sidekiq/worker.rb +2 -1
  37. data/lib/sidekiq.rb +87 -18
  38. data/sidekiq.gemspec +1 -1
  39. data/web/assets/javascripts/application.js +1 -1
  40. data/web/assets/javascripts/dashboard.js +0 -17
  41. data/web/assets/javascripts/graph.js +16 -0
  42. data/web/locales/en.yml +4 -0
  43. data/web/locales/pt-br.yml +27 -9
  44. data/web/views/_nav.erb +1 -1
  45. data/web/views/busy.erb +1 -1
  46. data/web/views/dashboard.erb +1 -0
  47. data/web/views/metrics.erb +59 -0
  48. data/web/views/metrics_for_job.erb +92 -0
  49. data/web/views/queue.erb +5 -1
  50. metadata +16 -6
  51. data/lib/sidekiq/exception_handler.rb +0 -27
  52. data/lib/sidekiq/util.rb +0 -108
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 70d899b76bdd764a2ec7e5f23b6d056494b58897daaf49db672daad3e0f60237
4
- data.tar.gz: daae0430ecaf8eb7f172c70e628581c20a17e1a7cb1a58170b9082fc3dde1ea2
3
+ metadata.gz: f2c97836bf831cdce9bbab92fbd7b0d01d3522c24f5cced0e0822a53b906d0af
4
+ data.tar.gz: 85c7f9abe6844a5471519ca235c65e84275bd2f8d33e395ec3f85bada091c699
5
5
  SHA512:
6
- metadata.gz: 930a0feb7ff47473eb995f8ba695468498afecb311c25296c93042ecfa00cd2bf48e19efd5ba775b4895c065705a344043e0c0e5d7b4115c2dceb1ec7cf341f9
7
- data.tar.gz: 14ab645609e7c9f3fa954432097cd46d6e9e74e5bddc9ed1541697d13f3399add407ffb5af23c89c82651793c97e2c54b8fd4f845ca20287ce6bf033fd9caed2
6
+ metadata.gz: 06e0cad7074f7288c4ec66ee0f8e38e85c556390f61a23dc9dc025459a0da57ed0641ae89c450862c2101045d4220e5e11ad8b7a23f5316fbfe7fb12fc04ec67
7
+ data.tar.gz: 7362db4b038735acda91a86017053cc5fec9b70f1bbc8b0650abb592b60598c49a07fbecd3ec14b18a9f6b1cf6e3b2e0810b64e70e833072b64248a945f45646
data/Changes.md CHANGED
@@ -2,6 +2,41 @@
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.2
6
+ ----------
7
+
8
+ - [Job Metrics are under active development, help wanted!](https://github.com/mperham/sidekiq/wiki/Metrics#contributing) **BETA**
9
+ - Add `Context` column on queue page which shows any CurrentAttributes [#5450]
10
+ - `sidekiq_retry_in` may now return `:discard` or `:kill` to dynamically stop job retries [#5406]
11
+ - Smarter sorting of processes in /busy Web UI [#5398]
12
+ - Fix broken hamburger menu in mobile UI [#5428]
13
+ - Require redis-rb 4.5.0. Note that Sidekiq will break if you use the
14
+ [`Redis.exists_returns_integer = false`](https://github.com/redis/redis-rb/blob/master/CHANGELOG.md#450) flag. [#5394]
15
+
16
+ 6.5.1
17
+ ----------
18
+
19
+ - Fix `push_bulk` breakage [#5387]
20
+
21
+ 6.5.0
22
+ ---------
23
+
24
+ - Substantial refactoring of Sidekiq server internals, part of a larger effort
25
+ 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).
26
+ - **Add beta support for the `redis-client` gem**. This will become the default Redis driver in Sidekiq 7.0. [#5298]
27
+ Read more: https://github.com/mperham/sidekiq/wiki/Using-redis-client
28
+ - **Add beta support for DB transaction-aware client** [#5291]
29
+ Add this line to your initializer and any jobs created during a transaction
30
+ will only be pushed to Redis **after the transaction commits**. You will need to add the
31
+ `after_commit_everywhere` gem to your Gemfile.
32
+ ```ruby
33
+ Sidekiq.transactional_push!
34
+ ```
35
+ This feature does not have a lot of production usage yet; please try it out and let us
36
+ know if you have any issues. It will be fully supported in Sidekiq 7.0 or removed if it
37
+ proves problematic.
38
+ - Fix regression with middleware arguments [#5312]
39
+
5
40
  6.4.2
6
41
  ---------
7
42
 
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
 
data/lib/sidekiq/api.rb CHANGED
@@ -3,9 +3,17 @@
3
3
  require "sidekiq"
4
4
 
5
5
  require "zlib"
6
+ require "set"
6
7
  require "base64"
8
+ require "sidekiq/metrics/deploy"
9
+ require "sidekiq/metrics/query"
7
10
 
8
11
  module Sidekiq
12
+ # Retrieve runtime statistics from Redis regarding
13
+ # this Sidekiq cluster.
14
+ #
15
+ # stat = Sidekiq::Stats.new
16
+ # stat.processed
9
17
  class Stats
10
18
  def initialize
11
19
  fetch_stats_fast!
@@ -52,6 +60,7 @@ module Sidekiq
52
60
  end
53
61
 
54
62
  # O(1) redis calls
63
+ # @api private
55
64
  def fetch_stats_fast!
56
65
  pipe1_res = Sidekiq.redis { |conn|
57
66
  conn.pipelined do |pipeline|
@@ -91,6 +100,7 @@ module Sidekiq
91
100
  end
92
101
 
93
102
  # O(number of processes + number of queues) redis calls
103
+ # @api private
94
104
  def fetch_stats_slow!
95
105
  processes = Sidekiq.redis { |conn|
96
106
  conn.sscan_each("processes").to_a
@@ -116,11 +126,13 @@ module Sidekiq
116
126
  @stats
117
127
  end
118
128
 
129
+ # @api private
119
130
  def fetch_stats!
120
131
  fetch_stats_fast!
121
132
  fetch_stats_slow!
122
133
  end
123
134
 
135
+ # @api private
124
136
  def reset(*stats)
125
137
  all = %w[failed processed]
126
138
  stats = stats.empty? ? all : all & stats.flatten.compact.map(&:to_s)
@@ -191,7 +203,7 @@ module Sidekiq
191
203
  stat_hash[dates[idx]] = value ? value.to_i : 0
192
204
  end
193
205
  end
194
- rescue Redis::CommandError
206
+ rescue RedisConnection.adapter::CommandError
195
207
  # mget will trigger a CROSSSLOT error when run against a Cluster
196
208
  # TODO Someone want to add Cluster support?
197
209
  end
@@ -202,9 +214,10 @@ module Sidekiq
202
214
  end
203
215
 
204
216
  ##
205
- # Encapsulates a queue within Sidekiq.
217
+ # Represents a queue within Sidekiq.
206
218
  # Allows enumeration of all jobs within the queue
207
- # and deletion of jobs.
219
+ # and deletion of jobs. NB: this queue data is real-time
220
+ # and is changing within Redis moment by moment.
208
221
  #
209
222
  # queue = Sidekiq::Queue.new("mailer")
210
223
  # queue.each do |job|
@@ -212,29 +225,34 @@ module Sidekiq
212
225
  # job.args # => [1, 2, 3]
213
226
  # job.delete if job.jid == 'abcdef1234567890'
214
227
  # end
215
- #
216
228
  class Queue
217
229
  include Enumerable
218
230
 
219
231
  ##
220
- # Return all known queues within Redis.
232
+ # Fetch all known queues within Redis.
221
233
  #
234
+ # @return [Array<Sidekiq::Queue>]
222
235
  def self.all
223
236
  Sidekiq.redis { |c| c.sscan_each("queues").to_a }.sort.map { |q| Sidekiq::Queue.new(q) }
224
237
  end
225
238
 
226
239
  attr_reader :name
227
240
 
241
+ # @param name [String] the name of the queue
228
242
  def initialize(name = "default")
229
243
  @name = name.to_s
230
244
  @rname = "queue:#{name}"
231
245
  end
232
246
 
247
+ # The current size of the queue within Redis.
248
+ # This value is real-time and can change between calls.
249
+ #
250
+ # @return [Integer] the size
233
251
  def size
234
252
  Sidekiq.redis { |con| con.llen(@rname) }
235
253
  end
236
254
 
237
- # Sidekiq Pro overrides this
255
+ # @return [Boolean] if the queue is currently paused
238
256
  def paused?
239
257
  false
240
258
  end
@@ -243,7 +261,7 @@ module Sidekiq
243
261
  # Calculates this queue's latency, the difference in seconds since the oldest
244
262
  # job in the queue was enqueued.
245
263
  #
246
- # @return Float
264
+ # @return [Float] in seconds
247
265
  def latency
248
266
  entry = Sidekiq.redis { |conn|
249
267
  conn.lrange(@rname, -1, -1)
@@ -279,12 +297,18 @@ module Sidekiq
279
297
  ##
280
298
  # Find the job with the given JID within this queue.
281
299
  #
282
- # This is a slow, inefficient operation. Do not use under
300
+ # This is a *slow, inefficient* operation. Do not use under
283
301
  # normal conditions.
302
+ #
303
+ # @param jid [String] the job_id to look for
304
+ # @return [Sidekiq::JobRecord]
305
+ # @return [nil] if not found
284
306
  def find_job(jid)
285
307
  detect { |j| j.jid == jid }
286
308
  end
287
309
 
310
+ # delete all jobs within this queue
311
+ # @return [Boolean] true
288
312
  def clear
289
313
  Sidekiq.redis do |conn|
290
314
  conn.multi do |transaction|
@@ -292,21 +316,35 @@ module Sidekiq
292
316
  transaction.srem("queues", name)
293
317
  end
294
318
  end
319
+ true
295
320
  end
296
321
  alias_method :💣, :clear
322
+
323
+ # :nodoc:
324
+ # @api private
325
+ def as_json(options = nil)
326
+ {name: name} # 5336
327
+ end
297
328
  end
298
329
 
299
330
  ##
300
- # Encapsulates a pending job within a Sidekiq queue or
301
- # sorted set.
331
+ # Represents a pending job within a Sidekiq queue.
302
332
  #
303
333
  # The job should be considered immutable but may be
304
334
  # removed from the queue via JobRecord#delete.
305
- #
306
335
  class JobRecord
336
+ # the parsed Hash of job data
337
+ # @!attribute [r] Item
307
338
  attr_reader :item
339
+ # the underlying String in Redis
340
+ # @!attribute [r] Value
308
341
  attr_reader :value
342
+ # the queue associated with this job
343
+ # @!attribute [r] Queue
344
+ attr_reader :queue
309
345
 
346
+ # :nodoc:
347
+ # @api private
310
348
  def initialize(item, queue_name = nil)
311
349
  @args = nil
312
350
  @value = item
@@ -314,6 +352,8 @@ module Sidekiq
314
352
  @queue = queue_name || @item["queue"]
315
353
  end
316
354
 
355
+ # :nodoc:
356
+ # @api private
317
357
  def parse(item)
318
358
  Sidekiq.load_json(item)
319
359
  rescue JSON::ParserError
@@ -325,6 +365,8 @@ module Sidekiq
325
365
  {}
326
366
  end
327
367
 
368
+ # This is the job class which Sidekiq will execute. If using ActiveJob,
369
+ # this class will be the ActiveJob adapter class rather than a specific job.
328
370
  def klass
329
371
  self["class"]
330
372
  end
@@ -412,15 +454,12 @@ module Sidekiq
412
454
  end
413
455
  end
414
456
 
415
- attr_reader :queue
416
-
417
457
  def latency
418
458
  now = Time.now.to_f
419
459
  now - (@item["enqueued_at"] || @item["created_at"] || now)
420
460
  end
421
461
 
422
- ##
423
- # Remove this job from the queue.
462
+ # Remove this job from the queue
424
463
  def delete
425
464
  count = Sidekiq.redis { |conn|
426
465
  conn.lrem("queue:#{@queue}", 1, @value)
@@ -428,6 +467,7 @@ module Sidekiq
428
467
  count != 0
429
468
  end
430
469
 
470
+ # Access arbitrary attributes within the job hash
431
471
  def [](name)
432
472
  # nil will happen if the JSON fails to parse.
433
473
  # We don't guarantee Sidekiq will work with bad job JSON but we should
@@ -442,7 +482,8 @@ module Sidekiq
442
482
  rescue => ex
443
483
  # #1761 in dev mode, it's possible to have jobs enqueued which haven't been loaded into
444
484
  # memory yet so the YAML can't be loaded.
445
- Sidekiq.logger.warn "Unable to load YAML: #{ex.message}" unless Sidekiq.options[:environment] == "development"
485
+ # TODO is this still necessary? Zeitwerk reloader should handle?
486
+ Sidekiq.logger.warn "Unable to load YAML: #{ex.message}" unless Sidekiq.config[:environment] == "development"
446
487
  default
447
488
  end
448
489
 
@@ -464,20 +505,28 @@ module Sidekiq
464
505
  end
465
506
  end
466
507
 
508
+ # Represents a job within a Redis sorted set where the score
509
+ # represents a timestamp associated with the job. This timestamp
510
+ # could be the scheduled time for it to run (e.g. scheduled set),
511
+ # or the expiration date after which the entry should be deleted (e.g. dead set).
467
512
  class SortedEntry < JobRecord
468
513
  attr_reader :score
469
514
  attr_reader :parent
470
515
 
516
+ # :nodoc:
517
+ # @api private
471
518
  def initialize(parent, score, item)
472
519
  super(item)
473
- @score = score
520
+ @score = Float(score)
474
521
  @parent = parent
475
522
  end
476
523
 
524
+ # The timestamp associated with this entry
477
525
  def at
478
526
  Time.at(score).utc
479
527
  end
480
528
 
529
+ # remove this entry from the sorted set
481
530
  def delete
482
531
  if @value
483
532
  @parent.delete_by_value(@parent.name, @value)
@@ -486,12 +535,17 @@ module Sidekiq
486
535
  end
487
536
  end
488
537
 
538
+ # Change the scheduled time for this job.
539
+ #
540
+ # @param at [Time] the new timestamp for this job
489
541
  def reschedule(at)
490
542
  Sidekiq.redis do |conn|
491
543
  conn.zincrby(@parent.name, at.to_f - @score, Sidekiq.dump_json(@item))
492
544
  end
493
545
  end
494
546
 
547
+ # Enqueue this job from the scheduled or dead set so it will
548
+ # be executed at some point in the near future.
495
549
  def add_to_queue
496
550
  remove_job do |message|
497
551
  msg = Sidekiq.load_json(message)
@@ -499,6 +553,8 @@ module Sidekiq
499
553
  end
500
554
  end
501
555
 
556
+ # enqueue this job from the retry set so it will be executed
557
+ # at some point in the near future.
502
558
  def retry
503
559
  remove_job do |message|
504
560
  msg = Sidekiq.load_json(message)
@@ -507,8 +563,7 @@ module Sidekiq
507
563
  end
508
564
  end
509
565
 
510
- ##
511
- # Place job in the dead set
566
+ # Move this job from its current set into the Dead set.
512
567
  def kill
513
568
  remove_job do |message|
514
569
  DeadSet.new.kill(message)
@@ -556,20 +611,32 @@ module Sidekiq
556
611
  end
557
612
  end
558
613
 
614
+ # Base class for all sorted sets within Sidekiq.
559
615
  class SortedSet
560
616
  include Enumerable
561
617
 
618
+ # Redis key of the set
619
+ # @!attribute [r] Name
562
620
  attr_reader :name
563
621
 
622
+ # :nodoc:
623
+ # @api private
564
624
  def initialize(name)
565
625
  @name = name
566
626
  @_size = size
567
627
  end
568
628
 
629
+ # real-time size of the set, will change
569
630
  def size
570
631
  Sidekiq.redis { |c| c.zcard(name) }
571
632
  end
572
633
 
634
+ # Scan through each element of the sorted set, yielding each to the supplied block.
635
+ # Please see Redis's <a href="https://redis.io/commands/scan/">SCAN documentation</a> for implementation details.
636
+ #
637
+ # @param match [String] a snippet or regexp to filter matches.
638
+ # @param count [Integer] number of elements to retrieve at a time, default 100
639
+ # @yieldparam [Sidekiq::SortedEntry] each entry
573
640
  def scan(match, count = 100)
574
641
  return to_enum(:scan, match, count) unless block_given?
575
642
 
@@ -581,18 +648,32 @@ module Sidekiq
581
648
  end
582
649
  end
583
650
 
651
+ # @return [Boolean] always true
584
652
  def clear
585
653
  Sidekiq.redis do |conn|
586
654
  conn.unlink(name)
587
655
  end
656
+ true
588
657
  end
589
658
  alias_method :💣, :clear
659
+
660
+ # :nodoc:
661
+ # @api private
662
+ def as_json(options = nil)
663
+ {name: name} # 5336
664
+ end
590
665
  end
591
666
 
667
+ # Base class for all sorted sets which contain jobs, e.g. scheduled, retry and dead.
668
+ # Sidekiq Pro and Enterprise add additional sorted sets which do not contain job data,
669
+ # e.g. Batches.
592
670
  class JobSet < SortedSet
593
- def schedule(timestamp, message)
671
+ # Add a job with the associated timestamp to this set.
672
+ # @param timestamp [Time] the score for the job
673
+ # @param job [Hash] the job data
674
+ def schedule(timestamp, job)
594
675
  Sidekiq.redis do |conn|
595
- conn.zadd(name, timestamp.to_f.to_s, Sidekiq.dump_json(message))
676
+ conn.zadd(name, timestamp.to_f.to_s, Sidekiq.dump_json(job))
596
677
  end
597
678
  end
598
679
 
@@ -606,7 +687,7 @@ module Sidekiq
606
687
  range_start = page * page_size + offset_size
607
688
  range_end = range_start + page_size - 1
608
689
  elements = Sidekiq.redis { |conn|
609
- conn.zrange name, range_start, range_end, with_scores: true
690
+ conn.zrange name, range_start, range_end, withscores: true
610
691
  }
611
692
  break if elements.empty?
612
693
  page -= 1
@@ -620,6 +701,10 @@ module Sidekiq
620
701
  ##
621
702
  # Fetch jobs that match a given time or Range. Job ID is an
622
703
  # optional second argument.
704
+ #
705
+ # @param score [Time,Range] a specific timestamp or range
706
+ # @param jid [String, optional] find a specific JID within the score
707
+ # @return [Array<SortedEntry>] any results found, can be empty
623
708
  def fetch(score, jid = nil)
624
709
  begin_score, end_score =
625
710
  if score.is_a?(Range)
@@ -629,7 +714,7 @@ module Sidekiq
629
714
  end
630
715
 
631
716
  elements = Sidekiq.redis { |conn|
632
- conn.zrangebyscore(name, begin_score, end_score, with_scores: true)
717
+ conn.zrangebyscore(name, begin_score, end_score, withscores: true)
633
718
  }
634
719
 
635
720
  elements.each_with_object([]) do |element, result|
@@ -641,7 +726,10 @@ module Sidekiq
641
726
 
642
727
  ##
643
728
  # Find the job with the given JID within this sorted set.
644
- # This is a slower O(n) operation. Do not use for app logic.
729
+ # *This is a slow O(n) operation*. Do not use for app logic.
730
+ #
731
+ # @param jid [String] the job identifier
732
+ # @return [SortedEntry] the record or nil
645
733
  def find_job(jid)
646
734
  Sidekiq.redis do |conn|
647
735
  conn.zscan_each(name, match: "*#{jid}*", count: 100) do |entry, score|
@@ -653,6 +741,8 @@ module Sidekiq
653
741
  nil
654
742
  end
655
743
 
744
+ # :nodoc:
745
+ # @api private
656
746
  def delete_by_value(name, value)
657
747
  Sidekiq.redis do |conn|
658
748
  ret = conn.zrem(name, value)
@@ -661,6 +751,8 @@ module Sidekiq
661
751
  end
662
752
  end
663
753
 
754
+ # :nodoc:
755
+ # @api private
664
756
  def delete_by_jid(score, jid)
665
757
  Sidekiq.redis do |conn|
666
758
  elements = conn.zrangebyscore(name, score, score)
@@ -681,10 +773,10 @@ module Sidekiq
681
773
  end
682
774
 
683
775
  ##
684
- # Allows enumeration of scheduled jobs within Sidekiq.
776
+ # The set of scheduled jobs within Sidekiq.
685
777
  # Based on this, you can search/filter for jobs. Here's an
686
- # example where I'm selecting all jobs of a certain type
687
- # and deleting them from the schedule queue.
778
+ # example where I'm selecting jobs based on some complex logic
779
+ # and deleting them from the scheduled set.
688
780
  #
689
781
  # r = Sidekiq::ScheduledSet.new
690
782
  # r.select do |scheduled|
@@ -699,7 +791,7 @@ module Sidekiq
699
791
  end
700
792
 
701
793
  ##
702
- # Allows enumeration of retries within Sidekiq.
794
+ # The set of retries within Sidekiq.
703
795
  # Based on this, you can search/filter for jobs. Here's an
704
796
  # example where I'm selecting all jobs of a certain type
705
797
  # and deleting them from the retry queue.
@@ -715,23 +807,29 @@ module Sidekiq
715
807
  super "retry"
716
808
  end
717
809
 
810
+ # Enqueues all jobs pending within the retry set.
718
811
  def retry_all
719
812
  each(&:retry) while size > 0
720
813
  end
721
814
 
815
+ # Kills all jobs pending within the retry set.
722
816
  def kill_all
723
817
  each(&:kill) while size > 0
724
818
  end
725
819
  end
726
820
 
727
821
  ##
728
- # Allows enumeration of dead jobs within Sidekiq.
822
+ # The set of dead jobs within Sidekiq. Dead jobs have failed all of
823
+ # their retries and are helding in this set pending some sort of manual
824
+ # fix. They will be removed after 6 months (dead_timeout) if not.
729
825
  #
730
826
  class DeadSet < JobSet
731
827
  def initialize
732
828
  super "dead"
733
829
  end
734
830
 
831
+ # Add the given job to the Dead set.
832
+ # @param message [String] the job data as JSON
735
833
  def kill(message, opts = {})
736
834
  now = Time.now.to_f
737
835
  Sidekiq.redis do |conn|
@@ -753,16 +851,21 @@ module Sidekiq
753
851
  true
754
852
  end
755
853
 
854
+ # Enqueue all dead jobs
756
855
  def retry_all
757
856
  each(&:retry) while size > 0
758
857
  end
759
858
 
859
+ # The maximum size of the Dead set. Older entries will be trimmed
860
+ # to stay within this limit. Default value is 10,000.
760
861
  def self.max_jobs
761
- Sidekiq.options[:dead_max_jobs]
862
+ Sidekiq[:dead_max_jobs]
762
863
  end
763
864
 
865
+ # The time limit for entries within the Dead set. Older entries will be thrown away.
866
+ # Default value is six months.
764
867
  def self.timeout
765
- Sidekiq.options[:dead_timeout_in_seconds]
868
+ Sidekiq[:dead_timeout_in_seconds]
766
869
  end
767
870
  end
768
871
 
@@ -771,18 +874,23 @@ module Sidekiq
771
874
  # right now. Each process sends a heartbeat to Redis every 5 seconds
772
875
  # so this set should be relatively accurate, barring network partitions.
773
876
  #
774
- # Yields a Sidekiq::Process.
877
+ # @yieldparam [Sidekiq::Process]
775
878
  #
776
879
  class ProcessSet
777
880
  include Enumerable
778
881
 
882
+ # :nodoc:
883
+ # @api private
779
884
  def initialize(clean_plz = true)
780
885
  cleanup if clean_plz
781
886
  end
782
887
 
783
888
  # Cleans up dead processes recorded in Redis.
784
889
  # Returns the number of processes cleaned.
890
+ # :nodoc:
891
+ # @api private
785
892
  def cleanup
893
+ return 0 unless Sidekiq.redis { |conn| conn.set("process_cleanup", "1", nx: true, ex: 60) }
786
894
  count = 0
787
895
  Sidekiq.redis do |conn|
788
896
  procs = conn.sscan_each("processes").to_a.sort
@@ -836,6 +944,7 @@ module Sidekiq
836
944
  # based on current heartbeat. #each does that and ensures the set only
837
945
  # contains Sidekiq processes which have sent a heartbeat within the last
838
946
  # 60 seconds.
947
+ # @return [Integer] current number of registered Sidekiq processes
839
948
  def size
840
949
  Sidekiq.redis { |conn| conn.scard("processes") }
841
950
  end
@@ -843,10 +952,12 @@ module Sidekiq
843
952
  # Total number of threads available to execute jobs.
844
953
  # For Sidekiq Enterprise customers this number (in production) must be
845
954
  # less than or equal to your licensed concurrency.
955
+ # @return [Integer] the sum of process concurrency
846
956
  def total_concurrency
847
957
  sum { |x| x["concurrency"].to_i }
848
958
  end
849
959
 
960
+ # @return [Integer] total amount of RSS memory consumed by Sidekiq processes
850
961
  def total_rss_in_kb
851
962
  sum { |x| x["rss"].to_i }
852
963
  end
@@ -855,6 +966,8 @@ module Sidekiq
855
966
  # Returns the identity of the current cluster leader or "" if no leader.
856
967
  # This is a Sidekiq Enterprise feature, will always return "" in Sidekiq
857
968
  # or Sidekiq Pro.
969
+ # @return [String] Identity of cluster leader
970
+ # @return [String] empty string if no leader
858
971
  def leader
859
972
  @leader ||= begin
860
973
  x = Sidekiq.redis { |c| c.get("dear-leader") }
@@ -881,6 +994,8 @@ module Sidekiq
881
994
  # 'identity' => <unique string identifying the process>,
882
995
  # }
883
996
  class Process
997
+ # :nodoc:
998
+ # @api private
884
999
  def initialize(hash)
885
1000
  @attribs = hash
886
1001
  end
@@ -905,18 +1020,31 @@ module Sidekiq
905
1020
  self["queues"]
906
1021
  end
907
1022
 
1023
+ # Signal this process to stop processing new jobs.
1024
+ # It will continue to execute jobs it has already fetched.
1025
+ # This method is *asynchronous* and it can take 5-10
1026
+ # seconds for the process to quiet.
908
1027
  def quiet!
909
1028
  signal("TSTP")
910
1029
  end
911
1030
 
1031
+ # Signal this process to shutdown.
1032
+ # It will shutdown within its configured :timeout value, default 25 seconds.
1033
+ # This method is *asynchronous* and it can take 5-10
1034
+ # seconds for the process to start shutting down.
912
1035
  def stop!
913
1036
  signal("TERM")
914
1037
  end
915
1038
 
1039
+ # Signal this process to log backtraces for all threads.
1040
+ # Useful if you have a frozen or deadlocked process which is
1041
+ # still sending a heartbeat.
1042
+ # This method is *asynchronous* and it can take 5-10 seconds.
916
1043
  def dump_threads
917
1044
  signal("TTIN")
918
1045
  end
919
1046
 
1047
+ # @return [Boolean] true if this process is quiet or shutting down
920
1048
  def stopping?
921
1049
  self["quiet"] == "true"
922
1050
  end