sidekiq 6.5.6 → 7.0.0.beta1

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 (89) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +16 -4
  3. data/{LICENSE → LICENSE.txt} +0 -0
  4. data/README.md +13 -12
  5. data/bin/sidekiq +3 -8
  6. data/bin/sidekiqload +15 -24
  7. data/lib/sidekiq/api.rb +55 -111
  8. data/lib/sidekiq/capsule.rb +110 -0
  9. data/lib/sidekiq/cli.rb +44 -47
  10. data/lib/sidekiq/client.rb +29 -16
  11. data/lib/sidekiq/component.rb +1 -0
  12. data/lib/sidekiq/config.rb +270 -0
  13. data/lib/sidekiq/deploy.rb +62 -0
  14. data/lib/sidekiq/embedded.rb +61 -0
  15. data/lib/sidekiq/fetch.rb +10 -11
  16. data/lib/sidekiq/job.rb +375 -10
  17. data/lib/sidekiq/job_logger.rb +1 -1
  18. data/lib/sidekiq/job_retry.rb +8 -8
  19. data/lib/sidekiq/job_util.rb +4 -4
  20. data/lib/sidekiq/launcher.rb +36 -46
  21. data/lib/sidekiq/logger.rb +1 -26
  22. data/lib/sidekiq/manager.rb +9 -11
  23. data/lib/sidekiq/metrics/query.rb +2 -2
  24. data/lib/sidekiq/metrics/shared.rb +4 -3
  25. data/lib/sidekiq/metrics/tracking.rb +18 -18
  26. data/lib/sidekiq/middleware/chain.rb +7 -9
  27. data/lib/sidekiq/middleware/current_attributes.rb +8 -13
  28. data/lib/sidekiq/pool.rb +7 -0
  29. data/lib/sidekiq/processor.rb +17 -26
  30. data/lib/sidekiq/redis_client_adapter.rb +9 -45
  31. data/lib/sidekiq/redis_connection.rb +11 -111
  32. data/lib/sidekiq/scheduled.rb +58 -25
  33. data/lib/sidekiq/testing.rb +4 -32
  34. data/lib/sidekiq/transaction_aware_client.rb +4 -5
  35. data/lib/sidekiq/version.rb +1 -1
  36. data/lib/sidekiq/web/application.rb +1 -1
  37. data/lib/sidekiq/web/csrf_protection.rb +1 -1
  38. data/lib/sidekiq/web/helpers.rb +5 -16
  39. data/lib/sidekiq/web.rb +2 -17
  40. data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
  41. data/lib/sidekiq.rb +52 -274
  42. data/sidekiq.gemspec +29 -5
  43. data/web/assets/javascripts/base-charts.js +106 -0
  44. data/web/assets/javascripts/dashboard-charts.js +166 -0
  45. data/web/assets/javascripts/dashboard.js +3 -223
  46. data/web/assets/javascripts/metrics.js +90 -116
  47. data/web/assets/stylesheets/application-rtl.css +2 -91
  48. data/web/assets/stylesheets/application.css +21 -296
  49. data/web/locales/ar.yml +70 -70
  50. data/web/locales/cs.yml +62 -62
  51. data/web/locales/da.yml +52 -52
  52. data/web/locales/de.yml +65 -65
  53. data/web/locales/el.yml +2 -7
  54. data/web/locales/en.yml +76 -70
  55. data/web/locales/es.yml +68 -68
  56. data/web/locales/fa.yml +65 -65
  57. data/web/locales/fr.yml +67 -67
  58. data/web/locales/he.yml +65 -64
  59. data/web/locales/hi.yml +59 -59
  60. data/web/locales/it.yml +53 -53
  61. data/web/locales/ja.yml +71 -68
  62. data/web/locales/ko.yml +52 -52
  63. data/web/locales/lt.yml +66 -66
  64. data/web/locales/nb.yml +61 -61
  65. data/web/locales/nl.yml +52 -52
  66. data/web/locales/pl.yml +45 -45
  67. data/web/locales/pt-br.yml +59 -69
  68. data/web/locales/pt.yml +51 -51
  69. data/web/locales/ru.yml +67 -66
  70. data/web/locales/sv.yml +53 -53
  71. data/web/locales/ta.yml +60 -60
  72. data/web/locales/uk.yml +62 -61
  73. data/web/locales/ur.yml +64 -64
  74. data/web/locales/vi.yml +67 -67
  75. data/web/locales/zh-cn.yml +37 -11
  76. data/web/locales/zh-tw.yml +42 -8
  77. data/web/views/_footer.erb +5 -2
  78. data/web/views/dashboard.erb +36 -5
  79. data/web/views/metrics.erb +30 -19
  80. data/web/views/metrics_for_job.erb +16 -34
  81. metadata +59 -30
  82. data/lib/sidekiq/delay.rb +0 -43
  83. data/lib/sidekiq/extensions/action_mailer.rb +0 -48
  84. data/lib/sidekiq/extensions/active_record.rb +0 -43
  85. data/lib/sidekiq/extensions/class_methods.rb +0 -43
  86. data/lib/sidekiq/extensions/generic_proxy.rb +0 -33
  87. data/lib/sidekiq/metrics/deploy.rb +0 -47
  88. data/lib/sidekiq/worker.rb +0 -367
  89. data/web/assets/javascripts/graph.js +0 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7e12ddc46413e3e476d620e04428a86476f4826d7802575110b5c3697a096137
4
- data.tar.gz: 802bdbc7c0d45a9b793222baca250e292ce852d67902446bc75a0961a36f5677
3
+ metadata.gz: 31722cec9da8b32488242bbcf40b46f3e2eaf8f9e5f5acefb4be306e6a3521e1
4
+ data.tar.gz: 625639dd35227dd5c9e36d04e93afbb3f8ae6372c532625453a0d681fac19a65
5
5
  SHA512:
6
- metadata.gz: 6180da0e7aefa1573d6b283c56ad365063b290afb5c10a15dc83fb367cb981391d8304acc9ebb1219279a749da71e0af8b37979baea770b0b1efeb04627e0e4c
7
- data.tar.gz: 35c51c58b73450c6bbd3479cc55d873ed54a6a1ce6a5b7414ca78fc807984acea11d4697ce8c05bdb2e9eb799c30dc7b377872b4c48a3de60bee5d6d71e07b3a
6
+ metadata.gz: 9471e077c2122b7b8fe94d075d1203d83d463608485852237ede31f9307b57233bb6cb0ba867f8556c080d61b01a5eb5efb7f1e3d68835e5bd16adc2630c65e1
7
+ data.tar.gz: 95b6c47592ba8641b4398859dca9c80b0d644c9e61cffec5482ff5741047daa9523f9cc5efb1974e197f3f06cab07321a5aca8b1838635372b3ea26e37cfca45
data/Changes.md CHANGED
@@ -2,6 +2,18 @@
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
+ HEAD
6
+ ----------
7
+
8
+ - Adjust CurrentAttributes to work with the String class name so we aren't referencing
9
+ the Class within a Rails initializer [#5536]
10
+
11
+ 6.5.7
12
+ ----------
13
+
14
+ - Updates for JA and ZH locales
15
+ - Further optimizations for scheduled polling [#5513]
16
+
5
17
  6.5.6
6
18
  ----------
7
19
 
@@ -564,7 +576,7 @@ Sidekiq::Middleware::Server::Logging -> Sidekiq::JobLogger
564
576
  - The `SomeWorker.set(options)` API was re-written to avoid thread-local state. [#2152]
565
577
  - Sidekiq Enterprise's encrypted jobs now display "[encrypted data]" in the Web UI instead
566
578
  of random hex bytes.
567
- - Please see the [5.0 Upgrade notes](5.0-Upgrade.md) for more detail.
579
+ - Please see the [5.0 Upgrade notes](docs/5.0-Upgrade.md) for more detail.
568
580
 
569
581
  4.2.10
570
582
  -----------
@@ -782,7 +794,7 @@ Sidekiq::Queues.clear_all
782
794
  - Sidekiq's internals have been completely overhauled for performance
783
795
  and to remove dependencies. This has resulted in major speedups, as
784
796
  [detailed on my blog](http://www.mikeperham.com/2015/10/14/optimizing-sidekiq/).
785
- - See the [4.0 upgrade notes](4.0-Upgrade.md) for more detail.
797
+ - See the [4.0 upgrade notes](docs/4.0-Upgrade.md) for more detail.
786
798
 
787
799
  3.5.4
788
800
  -----------
@@ -1049,7 +1061,7 @@ sidekiq_options :dead => false, :retry => 5
1049
1061
  3.0.0
1050
1062
  -----------
1051
1063
 
1052
- Please see [3.0-Upgrade.md](3.0-Upgrade.md) for more comprehensive upgrade notes.
1064
+ Please see [3.0-Upgrade.md](docs/3.0-Upgrade.md) for more comprehensive upgrade notes.
1053
1065
 
1054
1066
  - **Dead Job Queue** - jobs which run out of retries are now moved to a dead
1055
1067
  job queue. These jobs must be retried manually or they will expire
@@ -1093,7 +1105,7 @@ Sidekiq::Client.via(ConnectionPool.new { Redis.new }) do
1093
1105
  end
1094
1106
  ```
1095
1107
  **Sharding support does require a breaking change to client-side
1096
- middleware, see 3.0-Upgrade.md.**
1108
+ middleware, see docs/3.0-Upgrade.md.**
1097
1109
  - New Chinese, Greek, Swedish and Czech translations for the Web UI.
1098
1110
  - Updated most languages translations for the new UI features.
1099
1111
  - **Remove official Capistrano integration** - this integration has been
File without changes
data/README.md CHANGED
@@ -27,10 +27,10 @@ This benchmark can be found in `bin/sidekiqload` and assumes a Redis network lat
27
27
  Requirements
28
28
  -----------------
29
29
 
30
- - Redis: 4.0+
31
- - Ruby: MRI 2.5+ or JRuby 9.2+.
30
+ - Redis: 6.2+
31
+ - Ruby: MRI 2.7+ or JRuby 9.3+.
32
32
 
33
- Sidekiq 6.0 supports Rails 5.0+ but does not require it.
33
+ Sidekiq 7.0 supports Rails 6.0+ but does not require it.
34
34
 
35
35
 
36
36
  Installation
@@ -52,24 +52,26 @@ Sidekiq and see its features in action. Here's the Web UI:
52
52
  Want to Upgrade?
53
53
  -------------------
54
54
 
55
+ Use `bundle up sidekiq` to upgrade Sidekiq and all its dependencies.
56
+ Upgrade notes between each major version can be found in the `docs/` directory.
57
+
55
58
  I also sell Sidekiq Pro and Sidekiq Enterprise, extensions to Sidekiq which provide more
56
59
  features, a commercial-friendly license and allow you to support high
57
60
  quality open source development all at the same time. Please see the
58
61
  [Sidekiq](https://sidekiq.org/) homepage for more detail.
59
62
 
60
- Subscribe to the **[quarterly newsletter](https://tinyletter.com/sidekiq)** to stay informed about the latest
61
- features and changes to Sidekiq and its bigger siblings.
62
-
63
63
 
64
64
  Problems?
65
65
  -----------------
66
66
 
67
- **Please do not directly email any Sidekiq committers with questions or problems.** A community is best served when discussions are held in public.
67
+ **Please do not directly email any Sidekiq committers with questions or problems.**
68
+ A community is best served when discussions are held in public.
68
69
 
69
70
  If you have a problem, please review the [FAQ](https://github.com/mperham/sidekiq/wiki/FAQ) and [Troubleshooting](https://github.com/mperham/sidekiq/wiki/Problems-and-Troubleshooting) wiki pages.
70
71
  Searching the [issues](https://github.com/mperham/sidekiq/issues) for your problem is also a good idea.
71
72
 
72
- Sidekiq Pro and Sidekiq Enterprise customers get private email support. You can purchase at https://sidekiq.org; email support@contribsys.com for help.
73
+ Sidekiq Pro and Sidekiq Enterprise customers get private email support.
74
+ You can purchase at https://sidekiq.org; email support@contribsys.com for help.
73
75
 
74
76
  Useful resources:
75
77
 
@@ -77,7 +79,7 @@ Useful resources:
77
79
  * Occasional announcements are made to the [@sidekiq](https://twitter.com/sidekiq) Twitter account.
78
80
  * The [Sidekiq tag](https://stackoverflow.com/questions/tagged/sidekiq) on Stack Overflow has lots of useful Q & A.
79
81
 
80
- Every Friday morning is Sidekiq happy hour: I video chat and answer questions.
82
+ Every Friday morning is Sidekiq office hour: I video chat and answer questions.
81
83
  See the [Sidekiq support page](https://sidekiq.org/support.html) for details.
82
84
 
83
85
  Contributing
@@ -85,12 +87,11 @@ Contributing
85
87
 
86
88
  Please see [the contributing guidelines](https://github.com/mperham/sidekiq/blob/main/.github/contributing.md).
87
89
 
88
-
89
90
  License
90
91
  -----------------
91
92
 
92
- Please see [LICENSE](https://github.com/mperham/sidekiq/blob/main/LICENSE) for licensing details.
93
-
93
+ Please see [LICENSE.txt](https://github.com/mperham/sidekiq/blob/main/LICENSE.txt) for licensing details.
94
+ The license for Sidekiq Pro and Sidekiq Enterprise can be found in [COMM-LICENSE.txt](https://github.com/mperham/sidekiq/blob/main/COMM-LICENSE.txt).
94
95
 
95
96
  Author
96
97
  -----------------
data/bin/sidekiq CHANGED
@@ -10,7 +10,7 @@ def integrate_with_systemd
10
10
  return unless ENV["NOTIFY_SOCKET"]
11
11
 
12
12
  Sidekiq.configure_server do |config|
13
- Sidekiq.logger.info "Enabling systemd notification integration"
13
+ config.logger.info "Enabling systemd notification integration"
14
14
  require "sidekiq/sd_notify"
15
15
  config.on(:startup) do
16
16
  Sidekiq::SdNotify.ready
@@ -31,12 +31,7 @@ begin
31
31
  cli.run
32
32
  rescue => e
33
33
  raise e if $DEBUG
34
- if Sidekiq.error_handlers.length == 0
35
- warn e.message
36
- warn e.backtrace.join("\n")
37
- else
38
- cli.handle_exception e
39
- end
40
-
34
+ warn e.message
35
+ warn e.backtrace.join("\n")
41
36
  exit 1
42
37
  end
data/bin/sidekiqload CHANGED
@@ -8,18 +8,11 @@ $TESTING = false
8
8
  require "bundler/setup"
9
9
  Bundler.require(:default, :load_test)
10
10
 
11
- require_relative "../lib/sidekiq/cli"
12
- require_relative "../lib/sidekiq/launcher"
13
-
14
- if ENV["SIDEKIQ_REDIS_CLIENT"]
15
- Sidekiq::RedisConnection.adapter = :redis_client
16
- end
17
-
18
- Sidekiq.configure_server do |config|
19
- config.options[:concurrency] = 10
11
+ x = Sidekiq.configure_embed do |config|
20
12
  config.redis = {db: 13, port: 6380}
13
+ config.concurrency = 10
21
14
  # config.redis = { db: 13, port: 6380, driver: :hiredis}
22
- config.options[:queues] << "default"
15
+ config.queues = %w[default]
23
16
  config.logger.level = Logger::ERROR
24
17
  config.average_scheduled_poll_interval = 2
25
18
  config.reliable! if defined?(Sidekiq::Pro)
@@ -89,7 +82,7 @@ def Process.rss
89
82
  `ps -o rss= -p #{Process.pid}`.chomp.to_i
90
83
  end
91
84
 
92
- iter = 50
85
+ iter = 10
93
86
  count = 10_000
94
87
 
95
88
  iter.times do
@@ -101,8 +94,8 @@ Sidekiq.logger.error "Created #{count * iter} jobs"
101
94
  start = Time.now
102
95
 
103
96
  Monitoring = Thread.new do
104
- while true
105
- sleep 0.2
97
+ loop do
98
+ sleep 1.0
106
99
  qsize = Sidekiq.redis do |conn|
107
100
  conn.llen "queue:default"
108
101
  end
@@ -132,30 +125,28 @@ def with_latency(latency, &block)
132
125
  end
133
126
 
134
127
  begin
135
- # RubyProf::exclude_threads = [ Monitoring ]
128
+ # RubyProf.exclude_threads = [Monitoring]
136
129
  # RubyProf.start
137
- events = Sidekiq.options[:lifecycle_events][:startup]
138
- events.each(&:call)
139
- events.clear
140
-
130
+
141
131
  with_latency(Integer(ENV.fetch("LATENCY", "1"))) do
142
- launcher = Sidekiq::Launcher.new(Sidekiq.options)
143
- launcher.run
132
+ x.run
144
133
 
145
- while readable_io = IO.select([self_read])
134
+ while (readable_io = IO.select([self_read]))
146
135
  signal = readable_io.first[0].gets.strip
147
- handle_signal(launcher, signal)
136
+ handle_signal(x, signal)
148
137
  end
149
138
  end
150
- rescue SystemExit => e
139
+ rescue SystemExit
151
140
  # Sidekiq.logger.error("Profiling...")
152
141
  # result = RubyProf.stop
153
142
  # printer = RubyProf::GraphHtmlPrinter.new(result)
154
- # printer.print(File.new("output.html", "w"), :min_percent => 1)
143
+ # printer.print(File.new("output.html", "w"), min_percent: 1)
155
144
  # normal
156
145
  rescue => e
157
146
  raise e if $DEBUG
158
147
  warn e.message
159
148
  warn e.backtrace.join("\n")
160
149
  exit 1
150
+ ensure
151
+ x.stop
161
152
  end
data/lib/sidekiq/api.rb CHANGED
@@ -6,10 +6,18 @@ require "zlib"
6
6
  require "set"
7
7
  require "base64"
8
8
 
9
- if ENV["SIDEKIQ_METRICS_BETA"]
10
- require "sidekiq/metrics/deploy"
11
- require "sidekiq/metrics/query"
12
- end
9
+ require "sidekiq/metrics/query"
10
+
11
+ #
12
+ # Sidekiq's Data API provides a Ruby object model on top
13
+ # of Sidekiq's runtime data in Redis. This API should never
14
+ # be used within application code for business logic.
15
+ #
16
+ # The Sidekiq server process never uses this API: all data
17
+ # manipulation is done directly for performance reasons to
18
+ # ensure we are using Redis as efficiently as possible at
19
+ # every callsite.
20
+ #
13
21
 
14
22
  module Sidekiq
15
23
  # Retrieve runtime statistics from Redis regarding
@@ -59,7 +67,18 @@ module Sidekiq
59
67
  end
60
68
 
61
69
  def queues
62
- Sidekiq::Stats::Queues.new.lengths
70
+ Sidekiq.redis do |conn|
71
+ queues = conn.sscan("queues").to_a
72
+
73
+ lengths = conn.pipelined { |pipeline|
74
+ queues.each do |queue|
75
+ pipeline.llen("queue:#{queue}")
76
+ end
77
+ }
78
+
79
+ array_of_arrays = queues.zip(lengths).sort_by { |_, size| -size }
80
+ array_of_arrays.to_h
81
+ end
63
82
  end
64
83
 
65
84
  # O(1) redis calls
@@ -106,11 +125,11 @@ module Sidekiq
106
125
  # @api private
107
126
  def fetch_stats_slow!
108
127
  processes = Sidekiq.redis { |conn|
109
- conn.sscan_each("processes").to_a
128
+ conn.sscan("processes").to_a
110
129
  }
111
130
 
112
131
  queues = Sidekiq.redis { |conn|
113
- conn.sscan_each("queues").to_a
132
+ conn.sscan("queues").to_a
114
133
  }
115
134
 
116
135
  pipe2_res = Sidekiq.redis { |conn|
@@ -122,7 +141,7 @@ module Sidekiq
122
141
 
123
142
  s = processes.size
124
143
  workers_size = pipe2_res[0...s].sum(&:to_i)
125
- enqueued = pipe2_res[s..-1].sum(&:to_i)
144
+ enqueued = pipe2_res[s..].sum(&:to_i)
126
145
 
127
146
  @stats[:workers_size] = workers_size
128
147
  @stats[:enqueued] = enqueued
@@ -157,25 +176,8 @@ module Sidekiq
157
176
  @stats[s] || raise(ArgumentError, "Unknown stat #{s}")
158
177
  end
159
178
 
160
- class Queues
161
- def lengths
162
- Sidekiq.redis do |conn|
163
- queues = conn.sscan_each("queues").to_a
164
-
165
- lengths = conn.pipelined { |pipeline|
166
- queues.each do |queue|
167
- pipeline.llen("queue:#{queue}")
168
- end
169
- }
170
-
171
- array_of_arrays = queues.zip(lengths).sort_by { |_, size| -size }
172
- array_of_arrays.to_h
173
- end
174
- end
175
- end
176
-
177
179
  class History
178
- def initialize(days_previous, start_date = nil)
180
+ def initialize(days_previous, start_date = nil, pool: nil)
179
181
  # we only store five years of data in Redis
180
182
  raise ArgumentError if days_previous < 1 || days_previous > (5 * 365)
181
183
  @days_previous = days_previous
@@ -200,15 +202,10 @@ module Sidekiq
200
202
 
201
203
  keys = dates.map { |datestr| "stat:#{stat}:#{datestr}" }
202
204
 
203
- begin
204
- Sidekiq.redis do |conn|
205
- conn.mget(keys).each_with_index do |value, idx|
206
- stat_hash[dates[idx]] = value ? value.to_i : 0
207
- end
205
+ Sidekiq.redis do |conn|
206
+ conn.mget(keys).each_with_index do |value, idx|
207
+ stat_hash[dates[idx]] = value ? value.to_i : 0
208
208
  end
209
- rescue RedisConnection.adapter::CommandError
210
- # mget will trigger a CROSSSLOT error when run against a Cluster
211
- # TODO Someone want to add Cluster support?
212
209
  end
213
210
 
214
211
  stat_hash
@@ -236,7 +233,7 @@ module Sidekiq
236
233
  #
237
234
  # @return [Array<Sidekiq::Queue>]
238
235
  def self.all
239
- Sidekiq.redis { |c| c.sscan_each("queues").to_a }.sort.map { |q| Sidekiq::Queue.new(q) }
236
+ Sidekiq.redis { |c| c.sscan("queues").to_a }.sort.map { |q| Sidekiq::Queue.new(q) }
240
237
  end
241
238
 
242
239
  attr_reader :name
@@ -377,12 +374,7 @@ module Sidekiq
377
374
  def display_class
378
375
  # Unwrap known wrappers so they show up in a human-friendly manner in the Web UI
379
376
  @klass ||= self["display_class"] || begin
380
- case klass
381
- when /\ASidekiq::Extensions::Delayed/
382
- safe_load(args[0], klass) do |target, method, _|
383
- "#{target}.#{method}"
384
- end
385
- when "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper"
377
+ if klass == "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper"
386
378
  job_class = @item["wrapped"] || args[0]
387
379
  if job_class == "ActionMailer::DeliveryJob" || job_class == "ActionMailer::MailDeliveryJob"
388
380
  # MailerClass#mailer_method
@@ -398,16 +390,7 @@ module Sidekiq
398
390
 
399
391
  def display_args
400
392
  # Unwrap known wrappers so they show up in a human-friendly manner in the Web UI
401
- @display_args ||= case klass
402
- when /\ASidekiq::Extensions::Delayed/
403
- safe_load(args[0], args) do |_, _, arg, kwarg|
404
- if !kwarg || kwarg.empty?
405
- arg
406
- else
407
- [arg, kwarg]
408
- end
409
- end
410
- when "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper"
393
+ @display_args ||= if klass == "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper"
411
394
  job_args = self["wrapped"] ? args[0]["arguments"] : []
412
395
  if (self["wrapped"] || args[0]) == "ActionMailer::DeliveryJob"
413
396
  # remove MailerClass, mailer_method and 'deliver_now'
@@ -480,31 +463,10 @@ module Sidekiq
480
463
 
481
464
  private
482
465
 
483
- def safe_load(content, default)
484
- yield(*YAML.load(content))
485
- rescue => ex
486
- # #1761 in dev mode, it's possible to have jobs enqueued which haven't been loaded into
487
- # memory yet so the YAML can't be loaded.
488
- # TODO is this still necessary? Zeitwerk reloader should handle?
489
- Sidekiq.logger.warn "Unable to load YAML: #{ex.message}" unless Sidekiq.options[:environment] == "development"
490
- default
491
- end
492
-
493
466
  def uncompress_backtrace(backtrace)
494
- if backtrace.is_a?(Array)
495
- # Handle old jobs with raw Array backtrace format
496
- backtrace
497
- else
498
- decoded = Base64.decode64(backtrace)
499
- uncompressed = Zlib::Inflate.inflate(decoded)
500
- begin
501
- Sidekiq.load_json(uncompressed)
502
- rescue
503
- # Handle old jobs with marshalled backtrace format
504
- # TODO Remove in 7.x
505
- Marshal.load(uncompressed)
506
- end
507
- end
467
+ decoded = Base64.decode64(backtrace)
468
+ uncompressed = Zlib::Inflate.inflate(decoded)
469
+ Sidekiq.load_json(uncompressed)
508
470
  end
509
471
  end
510
472
 
@@ -645,7 +607,7 @@ module Sidekiq
645
607
 
646
608
  match = "*#{match}*" unless match.include?("*")
647
609
  Sidekiq.redis do |conn|
648
- conn.zscan_each(name, match: match, count: count) do |entry, score|
610
+ conn.zscan(name, match: match, count: count) do |entry, score|
649
611
  yield SortedEntry.new(self, score, entry)
650
612
  end
651
613
  end
@@ -735,7 +697,7 @@ module Sidekiq
735
697
  # @return [SortedEntry] the record or nil
736
698
  def find_job(jid)
737
699
  Sidekiq.redis do |conn|
738
- conn.zscan_each(name, match: "*#{jid}*", count: 100) do |entry, score|
700
+ conn.zscan(name, match: "*#{jid}*", count: 100) do |entry, score|
739
701
  job = JSON.parse(entry)
740
702
  matched = job["jid"] == jid
741
703
  return SortedEntry.new(self, score, entry) if matched
@@ -781,12 +743,8 @@ module Sidekiq
781
743
  # example where I'm selecting jobs based on some complex logic
782
744
  # and deleting them from the scheduled set.
783
745
  #
784
- # r = Sidekiq::ScheduledSet.new
785
- # r.select do |scheduled|
786
- # scheduled.klass == 'Sidekiq::Extensions::DelayedClass' &&
787
- # scheduled.args[0] == 'User' &&
788
- # scheduled.args[1] == 'setup_new_subscriber'
789
- # end.map(&:delete)
746
+ # See the API wiki page for usage notes and examples.
747
+ #
790
748
  class ScheduledSet < JobSet
791
749
  def initialize
792
750
  super "schedule"
@@ -799,12 +757,8 @@ module Sidekiq
799
757
  # example where I'm selecting all jobs of a certain type
800
758
  # and deleting them from the retry queue.
801
759
  #
802
- # r = Sidekiq::RetrySet.new
803
- # r.select do |retri|
804
- # retri.klass == 'Sidekiq::Extensions::DelayedClass' &&
805
- # retri.args[0] == 'User' &&
806
- # retri.args[1] == 'setup_new_subscriber'
807
- # end.map(&:delete)
760
+ # See the API wiki page for usage notes and examples.
761
+ #
808
762
  class RetrySet < JobSet
809
763
  def initialize
810
764
  super "retry"
@@ -838,8 +792,8 @@ module Sidekiq
838
792
  Sidekiq.redis do |conn|
839
793
  conn.multi do |transaction|
840
794
  transaction.zadd(name, now.to_s, message)
841
- transaction.zremrangebyscore(name, "-inf", now - self.class.timeout)
842
- transaction.zremrangebyrank(name, 0, - self.class.max_jobs)
795
+ transaction.zremrangebyscore(name, "-inf", now - Sidekiq::Config::DEFAULTS[:dead_timeout_in_seconds])
796
+ transaction.zremrangebyrank(name, 0, - Sidekiq::Config::DEFAULTS[:dead_max_jobs])
843
797
  end
844
798
  end
845
799
 
@@ -847,7 +801,7 @@ module Sidekiq
847
801
  job = Sidekiq.load_json(message)
848
802
  r = RuntimeError.new("Job killed by API")
849
803
  r.set_backtrace(caller)
850
- Sidekiq.death_handlers.each do |handle|
804
+ Sidekiq.default_configuration.death_handlers.each do |handle|
851
805
  handle.call(job, r)
852
806
  end
853
807
  end
@@ -858,18 +812,6 @@ module Sidekiq
858
812
  def retry_all
859
813
  each(&:retry) while size > 0
860
814
  end
861
-
862
- # The maximum size of the Dead set. Older entries will be trimmed
863
- # to stay within this limit. Default value is 10,000.
864
- def self.max_jobs
865
- Sidekiq[:dead_max_jobs]
866
- end
867
-
868
- # The time limit for entries within the Dead set. Older entries will be thrown away.
869
- # Default value is six months.
870
- def self.timeout
871
- Sidekiq[:dead_timeout_in_seconds]
872
- end
873
815
  end
874
816
 
875
817
  ##
@@ -893,10 +835,12 @@ module Sidekiq
893
835
  # :nodoc:
894
836
  # @api private
895
837
  def cleanup
838
+ # dont run cleanup more than once per minute
896
839
  return 0 unless Sidekiq.redis { |conn| conn.set("process_cleanup", "1", nx: true, ex: 60) }
840
+
897
841
  count = 0
898
842
  Sidekiq.redis do |conn|
899
- procs = conn.sscan_each("processes").to_a.sort
843
+ procs = conn.sscan("processes").to_a
900
844
  heartbeats = conn.pipelined { |pipeline|
901
845
  procs.each do |key|
902
846
  pipeline.hget(key, "info")
@@ -916,7 +860,7 @@ module Sidekiq
916
860
 
917
861
  def each
918
862
  result = Sidekiq.redis { |conn|
919
- procs = conn.sscan_each("processes").to_a.sort
863
+ procs = conn.sscan("processes").to_a.sort
920
864
 
921
865
  # We're making a tradeoff here between consuming more memory instead of
922
866
  # making more roundtrips to Redis, but if you have hundreds or thousands of workers,
@@ -1008,7 +952,7 @@ module Sidekiq
1008
952
  end
1009
953
 
1010
954
  def labels
1011
- Array(self["labels"])
955
+ self["labels"].to_a
1012
956
  end
1013
957
 
1014
958
  def [](key)
@@ -1091,13 +1035,13 @@ module Sidekiq
1091
1035
  def each(&block)
1092
1036
  results = []
1093
1037
  Sidekiq.redis do |conn|
1094
- procs = conn.sscan_each("processes").to_a
1038
+ procs = conn.sscan("processes").to_a
1095
1039
  procs.sort.each do |key|
1096
1040
  valid, workers = conn.pipelined { |pipeline|
1097
- pipeline.exists?(key)
1041
+ pipeline.exists(key)
1098
1042
  pipeline.hgetall("#{key}:work")
1099
1043
  }
1100
- next unless valid
1044
+ next unless valid > 0
1101
1045
  workers.each_pair do |tid, json|
1102
1046
  hsh = Sidekiq.load_json(json)
1103
1047
  p = hsh["payload"]
@@ -1119,7 +1063,7 @@ module Sidekiq
1119
1063
  # which can easily get out of sync with crashy processes.
1120
1064
  def size
1121
1065
  Sidekiq.redis do |conn|
1122
- procs = conn.sscan_each("processes").to_a
1066
+ procs = conn.sscan("processes").to_a
1123
1067
  if procs.empty?
1124
1068
  0
1125
1069
  else
@@ -0,0 +1,110 @@
1
+ require "sidekiq/component"
2
+
3
+ module Sidekiq
4
+ # A Sidekiq::Capsule is the set of resources necessary to
5
+ # process one or more queues with a given concurrency.
6
+ # One "default" Capsule is started but the user may declare additional
7
+ # Capsules in the initializer.
8
+ #
9
+ # To process a "single" queue with one thread so jobs are processed
10
+ # serially, you can do this:
11
+ #
12
+ # Sidekiq.configure_server do |config|
13
+ # config.capsule("single-threaded") do |cap|
14
+ # cap.concurrency = 1
15
+ # cap.queues = %w(single)
16
+ # end
17
+ # end
18
+ class Capsule
19
+ include Sidekiq::Component
20
+
21
+ attr_reader :name
22
+ attr_reader :queues
23
+ attr_accessor :concurrency
24
+
25
+ def initialize(name, config)
26
+ @name = name
27
+ @config = config
28
+ @queues = ["default"]
29
+ @concurrency = config[:concurrency]
30
+ end
31
+
32
+ def fetcher
33
+ @fetcher ||= begin
34
+ inst = (config[:fetch_class] || Sidekiq::BasicFetch).new(self)
35
+ inst.setup(config[:fetch_setup]) if inst.respond_to?(:setup)
36
+ inst
37
+ end
38
+ end
39
+
40
+ def stop
41
+ fetcher&.bulk_requeue([], nil)
42
+ end
43
+
44
+ def queues=(val)
45
+ @queues = Array(val).each_with_object([]) do |qstr, memo|
46
+ arr = qstr
47
+ arr = qstr.split(",") if qstr.is_a?(String)
48
+ name, weight = arr
49
+ [weight.to_i, 1].max.times do
50
+ memo << name
51
+ end
52
+ end
53
+ end
54
+
55
+ # Allow the middleware to be different per-capsule.
56
+ # Avoid if possible and add middleware globally so all
57
+ # capsules share the same chains. Easier to debug that way.
58
+ def client_middleware
59
+ @client_chain ||= config.client_middleware.copy_for(self)
60
+ yield @client_chain if block_given?
61
+ @client_chain
62
+ end
63
+
64
+ def server_middleware
65
+ @server_chain ||= config.server_middleware.copy_for(self)
66
+ yield @server_chain if block_given?
67
+ @server_chain
68
+ end
69
+
70
+ def redis_pool
71
+ Thread.current[:sidekiq_redis_pool] || local_redis_pool
72
+ end
73
+
74
+ def local_redis_pool
75
+ # connection pool is lazy, it will not create connections unless you actually need them
76
+ # so don't be skimpy!
77
+ @redis ||= config.new_redis_pool(@concurrency, name)
78
+ end
79
+
80
+ def redis
81
+ raise ArgumentError, "requires a block" unless block_given?
82
+ redis_pool.with do |conn|
83
+ retryable = true
84
+ begin
85
+ yield conn
86
+ rescue RedisClientAdapter::BaseError => ex
87
+ # 2550 Failover can cause the server to become a replica, need
88
+ # to disconnect and reopen the socket to get back to the primary.
89
+ # 4495 Use the same logic if we have a "Not enough replicas" error from the primary
90
+ # 4985 Use the same logic when a blocking command is force-unblocked
91
+ # The same retry logic is also used in client.rb
92
+ if retryable && ex.message =~ /READONLY|NOREPLICAS|UNBLOCKED/
93
+ conn.close
94
+ retryable = false
95
+ retry
96
+ end
97
+ raise
98
+ end
99
+ end
100
+ end
101
+
102
+ def lookup(name)
103
+ config.lookup(name)
104
+ end
105
+
106
+ def logger
107
+ config.logger
108
+ end
109
+ end
110
+ end