sidekiq 5.2.8 → 6.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of sidekiq might be problematic. Click here for more details.

Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +248 -0
  3. data/LICENSE +1 -1
  4. data/README.md +18 -34
  5. data/bin/sidekiq +26 -2
  6. data/bin/sidekiqload +32 -24
  7. data/bin/sidekiqmon +8 -0
  8. data/lib/generators/sidekiq/templates/worker_test.rb.erb +1 -1
  9. data/lib/generators/sidekiq/worker_generator.rb +21 -13
  10. data/lib/sidekiq/api.rb +310 -249
  11. data/lib/sidekiq/cli.rb +144 -180
  12. data/lib/sidekiq/client.rb +64 -48
  13. data/lib/sidekiq/delay.rb +5 -6
  14. data/lib/sidekiq/exception_handler.rb +10 -12
  15. data/lib/sidekiq/extensions/action_mailer.rb +13 -22
  16. data/lib/sidekiq/extensions/active_record.rb +13 -10
  17. data/lib/sidekiq/extensions/class_methods.rb +14 -11
  18. data/lib/sidekiq/extensions/generic_proxy.rb +6 -4
  19. data/lib/sidekiq/fetch.rb +38 -31
  20. data/lib/sidekiq/job.rb +8 -0
  21. data/lib/sidekiq/job_logger.rb +45 -7
  22. data/lib/sidekiq/job_retry.rb +64 -67
  23. data/lib/sidekiq/launcher.rb +146 -60
  24. data/lib/sidekiq/logger.rb +166 -0
  25. data/lib/sidekiq/manager.rb +11 -13
  26. data/lib/sidekiq/middleware/chain.rb +20 -8
  27. data/lib/sidekiq/middleware/i18n.rb +5 -7
  28. data/lib/sidekiq/monitor.rb +133 -0
  29. data/lib/sidekiq/paginator.rb +18 -14
  30. data/lib/sidekiq/processor.rb +71 -70
  31. data/lib/sidekiq/rails.rb +29 -37
  32. data/lib/sidekiq/redis_connection.rb +50 -48
  33. data/lib/sidekiq/scheduled.rb +35 -30
  34. data/lib/sidekiq/sd_notify.rb +149 -0
  35. data/lib/sidekiq/systemd.rb +24 -0
  36. data/lib/sidekiq/testing/inline.rb +2 -1
  37. data/lib/sidekiq/testing.rb +36 -27
  38. data/lib/sidekiq/util.rb +45 -16
  39. data/lib/sidekiq/version.rb +2 -1
  40. data/lib/sidekiq/web/action.rb +15 -11
  41. data/lib/sidekiq/web/application.rb +86 -76
  42. data/lib/sidekiq/web/csrf_protection.rb +180 -0
  43. data/lib/sidekiq/web/helpers.rb +114 -86
  44. data/lib/sidekiq/web/router.rb +23 -19
  45. data/lib/sidekiq/web.rb +61 -105
  46. data/lib/sidekiq/worker.rb +126 -102
  47. data/lib/sidekiq.rb +69 -44
  48. data/sidekiq.gemspec +23 -16
  49. data/web/assets/images/apple-touch-icon.png +0 -0
  50. data/web/assets/javascripts/application.js +25 -27
  51. data/web/assets/javascripts/dashboard.js +4 -23
  52. data/web/assets/stylesheets/application-dark.css +147 -0
  53. data/web/assets/stylesheets/application.css +37 -128
  54. data/web/locales/ar.yml +8 -2
  55. data/web/locales/de.yml +14 -2
  56. data/web/locales/en.yml +5 -0
  57. data/web/locales/es.yml +18 -2
  58. data/web/locales/fr.yml +10 -3
  59. data/web/locales/ja.yml +7 -1
  60. data/web/locales/lt.yml +83 -0
  61. data/web/locales/pl.yml +4 -4
  62. data/web/locales/ru.yml +4 -0
  63. data/web/locales/vi.yml +83 -0
  64. data/web/views/_job_info.erb +3 -2
  65. data/web/views/busy.erb +54 -20
  66. data/web/views/dashboard.erb +14 -6
  67. data/web/views/dead.erb +3 -3
  68. data/web/views/layout.erb +2 -0
  69. data/web/views/morgue.erb +9 -6
  70. data/web/views/queue.erb +11 -2
  71. data/web/views/queues.erb +10 -2
  72. data/web/views/retries.erb +11 -8
  73. data/web/views/retry.erb +3 -3
  74. data/web/views/scheduled.erb +5 -2
  75. metadata +32 -64
  76. data/.circleci/config.yml +0 -61
  77. data/.github/contributing.md +0 -32
  78. data/.github/issue_template.md +0 -11
  79. data/.gitignore +0 -15
  80. data/.travis.yml +0 -11
  81. data/3.0-Upgrade.md +0 -70
  82. data/4.0-Upgrade.md +0 -53
  83. data/5.0-Upgrade.md +0 -56
  84. data/COMM-LICENSE +0 -97
  85. data/Ent-Changes.md +0 -238
  86. data/Gemfile +0 -23
  87. data/Pro-2.0-Upgrade.md +0 -138
  88. data/Pro-3.0-Upgrade.md +0 -44
  89. data/Pro-4.0-Upgrade.md +0 -35
  90. data/Pro-Changes.md +0 -759
  91. data/Rakefile +0 -9
  92. data/bin/sidekiqctl +0 -20
  93. data/code_of_conduct.md +0 -50
  94. data/lib/sidekiq/core_ext.rb +0 -1
  95. data/lib/sidekiq/ctl.rb +0 -221
  96. data/lib/sidekiq/logging.rb +0 -122
  97. data/lib/sidekiq/middleware/server/active_record.rb +0 -23
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Sidekiq
3
4
  module Paginator
4
-
5
- def page(key, pageidx=1, page_size=25, opts=nil)
5
+ def page(key, pageidx = 1, page_size = 25, opts = nil)
6
6
  current_page = pageidx.to_i < 1 ? 1 : pageidx.to_i
7
7
  pageidx = current_page - 1
8
8
  total_size = 0
@@ -12,32 +12,36 @@ module Sidekiq
12
12
 
13
13
  Sidekiq.redis do |conn|
14
14
  type = conn.type(key)
15
+ rev = opts && opts[:reverse]
15
16
 
16
17
  case type
17
- when 'zset'
18
- rev = opts && opts[:reverse]
19
- total_size, items = conn.multi do
18
+ when "zset"
19
+ total_size, items = conn.multi {
20
20
  conn.zcard(key)
21
21
  if rev
22
- conn.zrevrange(key, starting, ending, :with_scores => true)
22
+ conn.zrevrange(key, starting, ending, with_scores: true)
23
23
  else
24
- conn.zrange(key, starting, ending, :with_scores => true)
24
+ conn.zrange(key, starting, ending, with_scores: true)
25
25
  end
26
- end
26
+ }
27
27
  [current_page, total_size, items]
28
- when 'list'
29
- total_size, items = conn.multi do
28
+ when "list"
29
+ total_size, items = conn.multi {
30
30
  conn.llen(key)
31
- conn.lrange(key, starting, ending)
32
- end
31
+ if rev
32
+ conn.lrange(key, -ending - 1, -starting - 1)
33
+ else
34
+ conn.lrange(key, starting, ending)
35
+ end
36
+ }
37
+ items.reverse! if rev
33
38
  [current_page, total_size, items]
34
- when 'none'
39
+ when "none"
35
40
  [1, 0, []]
36
41
  else
37
42
  raise "can't page a #{type}"
38
43
  end
39
44
  end
40
45
  end
41
-
42
46
  end
43
47
  end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
- require 'sidekiq/util'
3
- require 'sidekiq/fetch'
4
- require 'sidekiq/job_logger'
5
- require 'sidekiq/job_retry'
6
- require 'thread'
2
+
3
+ require "sidekiq/util"
4
+ require "sidekiq/fetch"
5
+ require "sidekiq/job_logger"
6
+ require "sidekiq/job_retry"
7
7
 
8
8
  module Sidekiq
9
9
  ##
@@ -23,33 +23,32 @@ module Sidekiq
23
23
  # to replace itself and exits.
24
24
  #
25
25
  class Processor
26
-
27
26
  include Util
28
27
 
29
28
  attr_reader :thread
30
29
  attr_reader :job
31
30
 
32
- def initialize(mgr)
31
+ def initialize(mgr, options)
33
32
  @mgr = mgr
34
33
  @down = false
35
34
  @done = false
36
35
  @job = nil
37
36
  @thread = nil
38
- @strategy = (mgr.options[:fetch] || Sidekiq::BasicFetch).new(mgr.options)
39
- @reloader = Sidekiq.options[:reloader]
40
- @logging = (mgr.options[:job_logger] || Sidekiq::JobLogger).new
37
+ @strategy = options[:fetch]
38
+ @reloader = options[:reloader] || proc { |&block| block.call }
39
+ @job_logger = (options[:job_logger] || Sidekiq::JobLogger).new
41
40
  @retrier = Sidekiq::JobRetry.new
42
41
  end
43
42
 
44
- def terminate(wait=false)
43
+ def terminate(wait = false)
45
44
  @done = true
46
- return if !@thread
45
+ return unless @thread
47
46
  @thread.value if wait
48
47
  end
49
48
 
50
- def kill(wait=false)
49
+ def kill(wait = false)
51
50
  @done = true
52
- return if !@thread
51
+ return unless @thread
53
52
  # unlike the other actors, terminate does not wait
54
53
  # for the thread to finish because we don't know how
55
54
  # long the job will take to finish. Instead we
@@ -66,16 +65,12 @@ module Sidekiq
66
65
  private unless $TESTING
67
66
 
68
67
  def run
69
- begin
70
- while !@done
71
- process_one
72
- end
73
- @mgr.processor_stopped(self)
74
- rescue Sidekiq::Shutdown
75
- @mgr.processor_stopped(self)
76
- rescue Exception => ex
77
- @mgr.processor_died(self, ex)
78
- end
68
+ process_one until @done
69
+ @mgr.processor_stopped(self)
70
+ rescue Sidekiq::Shutdown
71
+ @mgr.processor_stopped(self)
72
+ rescue Exception => ex
73
+ @mgr.processor_died(self, ex)
79
74
  end
80
75
 
81
76
  def process_one
@@ -85,14 +80,15 @@ module Sidekiq
85
80
  end
86
81
 
87
82
  def get_one
88
- begin
89
- work = @strategy.retrieve_work
90
- (logger.info { "Redis is online, #{::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - @down} sec downtime" }; @down = nil) if @down
91
- work
92
- rescue Sidekiq::Shutdown
93
- rescue => ex
94
- handle_fetch_exception(ex)
83
+ work = @strategy.retrieve_work
84
+ if @down
85
+ logger.info { "Redis is online, #{::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - @down} sec downtime" }
86
+ @down = nil
95
87
  end
88
+ work
89
+ rescue Sidekiq::Shutdown
90
+ rescue => ex
91
+ handle_fetch_exception(ex)
96
92
  end
97
93
 
98
94
  def fetch
@@ -106,7 +102,7 @@ module Sidekiq
106
102
  end
107
103
 
108
104
  def handle_fetch_exception(ex)
109
- if !@down
105
+ unless @down
110
106
  @down = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
111
107
  logger.error("Error fetching job: #{ex}")
112
108
  handle_exception(ex)
@@ -115,25 +111,28 @@ module Sidekiq
115
111
  nil
116
112
  end
117
113
 
118
- def dispatch(job_hash, queue)
114
+ def dispatch(job_hash, queue, jobstr)
119
115
  # since middleware can mutate the job hash
120
- # we clone here so we report the original
116
+ # we need to clone it to report the original
121
117
  # job structure to the Web UI
122
- pristine = cloned(job_hash)
123
-
124
- Sidekiq::Logging.with_job_hash_context(job_hash) do
125
- @retrier.global(pristine, queue) do
126
- @logging.call(job_hash, queue) do
127
- stats(pristine, queue) do
118
+ # or to push back to redis when retrying.
119
+ # To avoid costly and, most of the time, useless cloning here,
120
+ # we pass original String of JSON to respected methods
121
+ # to re-parse it there if we need access to the original, untouched job
122
+
123
+ @job_logger.prepare(job_hash) do
124
+ @retrier.global(jobstr, queue) do
125
+ @job_logger.call(job_hash, queue) do
126
+ stats(jobstr, queue) do
128
127
  # Rails 5 requires a Reloader to wrap code execution. In order to
129
128
  # constantize the worker and instantiate an instance, we have to call
130
129
  # the Reloader. It handles code loading, db connection management, etc.
131
130
  # Effectively this block denotes a "unit of work" to Rails.
132
131
  @reloader.call do
133
- klass = constantize(job_hash['class'])
132
+ klass = constantize(job_hash["class"])
134
133
  worker = klass.new
135
- worker.jid = job_hash['jid']
136
- @retrier.local(worker, pristine, queue) do
134
+ worker.jid = job_hash["jid"]
135
+ @retrier.local(worker, jobstr, queue) do
137
136
  yield worker
138
137
  end
139
138
  end
@@ -152,39 +151,44 @@ module Sidekiq
152
151
  begin
153
152
  job_hash = Sidekiq.load_json(jobstr)
154
153
  rescue => ex
155
- handle_exception(ex, { :context => "Invalid JSON for job", :jobstr => jobstr })
154
+ handle_exception(ex, {context: "Invalid JSON for job", jobstr: jobstr})
156
155
  # we can't notify because the job isn't a valid hash payload.
157
156
  DeadSet.new.kill(jobstr, notify_failure: false)
158
157
  return work.acknowledge
159
158
  end
160
159
 
161
- ack = true
160
+ ack = false
162
161
  begin
163
- dispatch(job_hash, queue) do |worker|
162
+ dispatch(job_hash, queue, jobstr) do |worker|
164
163
  Sidekiq.server_middleware.invoke(worker, job_hash, queue) do
165
- execute_job(worker, cloned(job_hash['args']))
164
+ execute_job(worker, job_hash["args"])
166
165
  end
167
166
  end
167
+ ack = true
168
168
  rescue Sidekiq::Shutdown
169
169
  # Had to force kill this job because it didn't finish
170
170
  # within the timeout. Don't acknowledge the work since
171
171
  # we didn't properly finish it.
172
- ack = false
173
172
  rescue Sidekiq::JobRetry::Handled => h
174
173
  # this is the common case: job raised error and Sidekiq::JobRetry::Handled
175
174
  # signals that we created a retry successfully. We can acknowlege the job.
176
- e = h.cause ? h.cause : h
177
- handle_exception(e, { :context => "Job raised exception", :job => job_hash, :jobstr => jobstr })
175
+ ack = true
176
+ e = h.cause || h
177
+ handle_exception(e, {context: "Job raised exception", job: job_hash, jobstr: jobstr})
178
178
  raise e
179
179
  rescue Exception => ex
180
180
  # Unexpected error! This is very bad and indicates an exception that got past
181
181
  # the retry subsystem (e.g. network partition). We won't acknowledge the job
182
182
  # so it can be rescued when using Sidekiq Pro.
183
- ack = false
184
- handle_exception(ex, { :context => "Internal exception!", :job => job_hash, :jobstr => jobstr })
185
- raise e
183
+ handle_exception(ex, {context: "Internal exception!", job: job_hash, jobstr: jobstr})
184
+ raise ex
186
185
  ensure
187
- work.acknowledge if ack
186
+ if ack
187
+ # We don't want a shutdown signal to interrupt job acknowledgment.
188
+ Thread.handle_interrupt(Sidekiq::Shutdown => :never) do
189
+ work.acknowledge
190
+ end
191
+ end
188
192
  end
189
193
  end
190
194
 
@@ -201,12 +205,16 @@ module Sidekiq
201
205
  @lock = Mutex.new
202
206
  end
203
207
 
204
- def incr(amount=1)
205
- @lock.synchronize { @value = @value + amount }
208
+ def incr(amount = 1)
209
+ @lock.synchronize { @value += amount }
206
210
  end
207
211
 
208
212
  def reset
209
- @lock.synchronize { val = @value; @value = 0; val }
213
+ @lock.synchronize {
214
+ val = @value
215
+ @value = 0
216
+ val
217
+ }
210
218
  end
211
219
  end
212
220
 
@@ -242,9 +250,8 @@ module Sidekiq
242
250
  FAILURE = Counter.new
243
251
  WORKER_STATE = SharedWorkerState.new
244
252
 
245
- def stats(job_hash, queue)
246
- tid = Sidekiq::Logging.tid
247
- WORKER_STATE.set(tid, {:queue => queue, :payload => job_hash, :run_at => Time.now.to_i })
253
+ def stats(jobstr, queue)
254
+ WORKER_STATE.set(tid, {queue: queue, payload: jobstr, run_at: Time.now.to_i})
248
255
 
249
256
  begin
250
257
  yield
@@ -257,23 +264,17 @@ module Sidekiq
257
264
  end
258
265
  end
259
266
 
260
- # Deep clone the arguments passed to the worker so that if
261
- # the job fails, what is pushed back onto Redis hasn't
262
- # been mutated by the worker.
263
- def cloned(thing)
264
- Marshal.load(Marshal.dump(thing))
265
- end
266
-
267
267
  def constantize(str)
268
- names = str.split('::')
268
+ return Object.const_get(str) unless str.include?("::")
269
+
270
+ names = str.split("::")
269
271
  names.shift if names.empty? || names.first.empty?
270
272
 
271
273
  names.inject(Object) do |constant, name|
272
274
  # the false flag limits search for name to under the constant namespace
273
275
  # which mimics Rails' behaviour
274
- constant.const_defined?(name, false) ? constant.const_get(name, false) : constant.const_missing(name)
276
+ constant.const_get(name, false)
275
277
  end
276
278
  end
277
-
278
279
  end
279
280
  end
data/lib/sidekiq/rails.rb CHANGED
@@ -1,38 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "sidekiq/worker"
4
+
3
5
  module Sidekiq
4
6
  class Rails < ::Rails::Engine
5
- # We need to setup this up before any application configuration which might
6
- # change Sidekiq middleware.
7
- #
8
- # This hook happens after `Rails::Application` is inherited within
9
- # config/application.rb and before config is touched, usually within the
10
- # class block. Definitely before config/environments/*.rb and
11
- # config/initializers/*.rb.
12
- config.before_configuration do
13
- if ::Rails::VERSION::MAJOR < 5 && defined?(::ActiveRecord)
14
- Sidekiq.server_middleware do |chain|
15
- require 'sidekiq/middleware/server/active_record'
16
- chain.add Sidekiq::Middleware::Server::ActiveRecord
17
- end
18
- end
19
- end
20
-
21
- config.after_initialize do
22
- # This hook happens after all initializers are run, just before returning
23
- # from config/environment.rb back to sidekiq/cli.rb.
24
- # We have to add the reloader after initialize to see if cache_classes has
25
- # been turned on.
26
- #
27
- # None of this matters on the client-side, only within the Sidekiq process itself.
28
- #
29
- Sidekiq.configure_server do |_|
30
- if ::Rails::VERSION::MAJOR >= 5
31
- Sidekiq.options[:reloader] = Sidekiq::Rails::Reloader.new
32
- end
33
- end
34
- end
35
-
36
7
  class Reloader
37
8
  def initialize(app = ::Rails.application)
38
9
  @app = app
@@ -48,11 +19,32 @@ module Sidekiq
48
19
  "#<Sidekiq::Rails::Reloader @app=#{@app.class.name}>"
49
20
  end
50
21
  end
51
- end if defined?(::Rails)
52
- end
53
22
 
54
- if defined?(::Rails) && ::Rails::VERSION::MAJOR < 4
55
- $stderr.puts("**************************************************")
56
- $stderr.puts("⛔️ WARNING: Sidekiq server is no longer supported by Rails 3.2 - please ensure your server/workers are updated")
57
- $stderr.puts("**************************************************")
23
+ # By including the Options module, we allow AJs to directly control sidekiq features
24
+ # via the *sidekiq_options* class method and, for instance, not use AJ's retry system.
25
+ # AJ retries don't show up in the Sidekiq UI Retries tab, save any error data, can't be
26
+ # manually retried, don't automatically die, etc.
27
+ #
28
+ # class SomeJob < ActiveJob::Base
29
+ # queue_as :default
30
+ # sidekiq_options retry: 3, backtrace: 10
31
+ # def perform
32
+ # end
33
+ # end
34
+ initializer "sidekiq.active_job_integration" do
35
+ ActiveSupport.on_load(:active_job) do
36
+ include ::Sidekiq::Worker::Options unless respond_to?(:sidekiq_options)
37
+ end
38
+ end
39
+
40
+ # This hook happens after all initializers are run, just before returning
41
+ # from config/environment.rb back to sidekiq/cli.rb.
42
+ #
43
+ # None of this matters on the client-side, only within the Sidekiq process itself.
44
+ config.after_initialize do
45
+ Sidekiq.configure_server do |_|
46
+ Sidekiq.options[:reloader] = Sidekiq::Rails::Reloader.new
47
+ end
48
+ end
49
+ end
58
50
  end
@@ -1,37 +1,38 @@
1
1
  # frozen_string_literal: true
2
- require 'connection_pool'
3
- require 'redis'
4
- require 'uri'
2
+
3
+ require "connection_pool"
4
+ require "redis"
5
+ require "uri"
5
6
 
6
7
  module Sidekiq
7
8
  class RedisConnection
8
9
  class << self
10
+ def create(options = {})
11
+ symbolized_options = options.transform_keys(&:to_sym)
9
12
 
10
- def create(options={})
11
- options.keys.each do |key|
12
- options[key.to_sym] = options.delete(key)
13
+ if !symbolized_options[:url] && (u = determine_redis_provider)
14
+ symbolized_options[:url] = u
13
15
  end
14
16
 
15
- options[:id] = "Sidekiq-#{Sidekiq.server? ? "server" : "client"}-PID-#{$$}" if !options.has_key?(:id)
16
- options[:url] ||= determine_redis_provider
17
-
18
- size = if options[:size]
19
- options[:size]
20
- elsif Sidekiq.server?
21
- Sidekiq.options[:concurrency] + 5
22
- elsif ENV['RAILS_MAX_THREADS']
23
- Integer(ENV['RAILS_MAX_THREADS'])
24
- else
25
- 5
26
- end
17
+ size = if symbolized_options[:size]
18
+ symbolized_options[:size]
19
+ elsif Sidekiq.server?
20
+ # Give ourselves plenty of connections. pool is lazy
21
+ # so we won't create them until we need them.
22
+ Sidekiq.options[:concurrency] + 5
23
+ elsif ENV["RAILS_MAX_THREADS"]
24
+ Integer(ENV["RAILS_MAX_THREADS"])
25
+ else
26
+ 5
27
+ end
27
28
 
28
29
  verify_sizing(size, Sidekiq.options[:concurrency]) if Sidekiq.server?
29
30
 
30
- pool_timeout = options[:pool_timeout] || 1
31
- log_info(options)
31
+ pool_timeout = symbolized_options[:pool_timeout] || 1
32
+ log_info(symbolized_options)
32
33
 
33
- ConnectionPool.new(:timeout => pool_timeout, :size => size) do
34
- build_client(options)
34
+ ConnectionPool.new(timeout: pool_timeout, size: size) do
35
+ build_client(symbolized_options)
35
36
  end
36
37
  end
37
38
 
@@ -46,7 +47,7 @@ module Sidekiq
46
47
  # - enterprise's leader election
47
48
  # - enterprise's cron support
48
49
  def verify_sizing(size, concurrency)
49
- raise ArgumentError, "Your Redis connection pool is too small for Sidekiq to work. Your pool has #{size} connections but must have at least #{concurrency + 2}" if size <= concurrency
50
+ raise ArgumentError, "Your Redis connection pool is too small for Sidekiq to work. Your pool has #{size} connections but must have at least #{concurrency + 2}" if size < (concurrency + 2)
50
51
  end
51
52
 
52
53
  def build_client(options)
@@ -55,8 +56,8 @@ module Sidekiq
55
56
  client = Redis.new client_opts(options)
56
57
  if namespace
57
58
  begin
58
- require 'redis/namespace'
59
- Redis::Namespace.new(namespace, :redis => client)
59
+ require "redis/namespace"
60
+ Redis::Namespace.new(namespace, redis: client)
60
61
  rescue LoadError
61
62
  Sidekiq.logger.error("Your Redis configuration uses the namespace '#{namespace}' but the redis-namespace gem is not included in the Gemfile." \
62
63
  "Add the gem to your Gemfile to continue using a namespace. Otherwise, remove the namespace parameter.")
@@ -78,7 +79,7 @@ module Sidekiq
78
79
  opts.delete(:network_timeout)
79
80
  end
80
81
 
81
- opts[:driver] ||= Redis::Connection.drivers.last || 'ruby'
82
+ opts[:driver] ||= Redis::Connection.drivers.last || "ruby"
82
83
 
83
84
  # Issue #3303, redis-rb will silently retry an operation.
84
85
  # This can lead to duplicate jobs if Sidekiq::Client's LPUSH
@@ -91,9 +92,15 @@ module Sidekiq
91
92
  end
92
93
 
93
94
  def log_info(options)
94
- # Don't log Redis AUTH password
95
95
  redacted = "REDACTED"
96
- scrubbed_options = options.dup
96
+
97
+ # deep clone so we can muck with these options all we want
98
+ #
99
+ # exclude SSL params from dump-and-load because some information isn't
100
+ # safely dumpable in current Rubies
101
+ keys = options.keys
102
+ keys.delete(:ssl_params)
103
+ scrubbed_options = Marshal.load(Marshal.dump(options.slice(*keys)))
97
104
  if scrubbed_options[:url] && (uri = URI.parse(scrubbed_options[:url])) && uri.password
98
105
  uri.password = redacted
99
106
  scrubbed_options[:url] = uri.to_s
@@ -101,6 +108,9 @@ module Sidekiq
101
108
  if scrubbed_options[:password]
102
109
  scrubbed_options[:password] = redacted
103
110
  end
111
+ scrubbed_options[:sentinels]&.each do |sentinel|
112
+ sentinel[:password] = redacted if sentinel[:password]
113
+ end
104
114
  if Sidekiq.server?
105
115
  Sidekiq.logger.info("Booting Sidekiq #{Sidekiq::VERSION} with redis options #{scrubbed_options}")
106
116
  else
@@ -115,30 +125,22 @@ module Sidekiq
115
125
  # REDIS_PROVIDER=MY_REDIS_URL
116
126
  # and Sidekiq will find your custom URL variable with no custom
117
127
  # initialization code at all.
118
- p = ENV['REDIS_PROVIDER']
119
- if p && p =~ /\:/
120
- Sidekiq.logger.error <<-EOM
121
-
122
- #################################################################################
123
-
124
- REDIS_PROVIDER should be set to the **name** of the variable which contains the Redis URL, not a URL itself.
125
- Platforms like Heroku sell addons that publish a *_URL variable. You tell Sidekiq with REDIS_PROVIDER, e.g.:
126
-
127
- REDIS_PROVIDER=REDISTOGO_URL
128
- REDISTOGO_URL=redis://somehost.example.com:6379/4
129
-
130
- Use REDIS_URL if you wish to point Sidekiq to a URL directly.
131
-
132
- This configuration error will crash starting in Sidekiq 5.3.
133
-
134
- #################################################################################
135
- EOM
128
+ #
129
+ p = ENV["REDIS_PROVIDER"]
130
+ if p && p =~ /:/
131
+ raise <<~EOM
132
+ REDIS_PROVIDER should be set to the name of the variable which contains the Redis URL, not a URL itself.
133
+ Platforms like Heroku will sell addons that publish a *_URL variable. You need to tell Sidekiq with REDIS_PROVIDER, e.g.:
134
+
135
+ REDISTOGO_URL=redis://somehost.example.com:6379/4
136
+ REDIS_PROVIDER=REDISTOGO_URL
137
+ EOM
136
138
  end
139
+
137
140
  ENV[
138
- ENV['REDIS_PROVIDER'] || 'REDIS_URL'
141
+ p || "REDIS_URL"
139
142
  ]
140
143
  end
141
-
142
144
  end
143
145
  end
144
146
  end