sidekiq 6.4.0 → 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.

Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +54 -1
  3. data/README.md +6 -1
  4. data/bin/sidekiq +3 -3
  5. data/bin/sidekiqload +70 -66
  6. data/bin/sidekiqmon +1 -1
  7. data/lib/sidekiq/.DS_Store +0 -0
  8. data/lib/sidekiq/api.rb +109 -78
  9. data/lib/sidekiq/cli.rb +47 -38
  10. data/lib/sidekiq/client.rb +42 -28
  11. data/lib/sidekiq/component.rb +64 -0
  12. data/lib/sidekiq/delay.rb +2 -2
  13. data/lib/sidekiq/extensions/action_mailer.rb +2 -2
  14. data/lib/sidekiq/extensions/active_record.rb +2 -2
  15. data/lib/sidekiq/extensions/class_methods.rb +2 -2
  16. data/lib/sidekiq/extensions/generic_proxy.rb +3 -3
  17. data/lib/sidekiq/fetch.rb +18 -16
  18. data/lib/sidekiq/job_logger.rb +15 -27
  19. data/lib/sidekiq/job_retry.rb +29 -28
  20. data/lib/sidekiq/job_util.rb +15 -9
  21. data/lib/sidekiq/launcher.rb +54 -52
  22. data/lib/sidekiq/logger.rb +8 -18
  23. data/lib/sidekiq/manager.rb +28 -25
  24. data/lib/sidekiq/middleware/chain.rb +22 -13
  25. data/lib/sidekiq/middleware/current_attributes.rb +4 -0
  26. data/lib/sidekiq/middleware/i18n.rb +6 -4
  27. data/lib/sidekiq/middleware/modules.rb +21 -0
  28. data/lib/sidekiq/monitor.rb +1 -1
  29. data/lib/sidekiq/paginator.rb +8 -8
  30. data/lib/sidekiq/processor.rb +38 -38
  31. data/lib/sidekiq/rails.rb +15 -8
  32. data/lib/sidekiq/redis_client_adapter.rb +154 -0
  33. data/lib/sidekiq/redis_connection.rb +81 -48
  34. data/lib/sidekiq/ring_buffer.rb +29 -0
  35. data/lib/sidekiq/scheduled.rb +11 -10
  36. data/lib/sidekiq/testing/inline.rb +4 -4
  37. data/lib/sidekiq/testing.rb +37 -36
  38. data/lib/sidekiq/transaction_aware_client.rb +45 -0
  39. data/lib/sidekiq/version.rb +1 -1
  40. data/lib/sidekiq/web/csrf_protection.rb +2 -2
  41. data/lib/sidekiq/web/helpers.rb +5 -5
  42. data/lib/sidekiq/web.rb +3 -3
  43. data/lib/sidekiq/worker.rb +20 -17
  44. data/lib/sidekiq.rb +98 -30
  45. data/web/assets/javascripts/application.js +58 -26
  46. data/web/assets/stylesheets/application.css +1 -0
  47. data/web/locales/pt-br.yml +27 -9
  48. data/web/views/_summary.erb +1 -1
  49. data/web/views/busy.erb +3 -3
  50. metadata +9 -5
  51. data/lib/sidekiq/exception_handler.rb +0 -27
  52. data/lib/sidekiq/util.rb +0 -108
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "sidekiq/util"
4
3
  require "sidekiq/fetch"
5
4
  require "sidekiq/job_logger"
6
5
  require "sidekiq/job_retry"
@@ -11,33 +10,34 @@ module Sidekiq
11
10
  #
12
11
  # 1. fetches a job from Redis
13
12
  # 2. executes the job
14
- # a. instantiate the Worker
13
+ # a. instantiate the job class
15
14
  # b. run the middleware chain
16
15
  # c. call #perform
17
16
  #
18
- # A Processor can exit due to shutdown (processor_stopped)
19
- # or due to an error during job execution (processor_died)
17
+ # A Processor can exit due to shutdown or due to
18
+ # an error during job execution.
20
19
  #
21
20
  # If an error occurs in the job execution, the
22
21
  # Processor calls the Manager to create a new one
23
22
  # to replace itself and exits.
24
23
  #
25
24
  class Processor
26
- include Util
25
+ include Sidekiq::Component
27
26
 
28
27
  attr_reader :thread
29
28
  attr_reader :job
30
29
 
31
- def initialize(mgr, options)
32
- @mgr = mgr
30
+ def initialize(options, &block)
31
+ @callback = block
33
32
  @down = false
34
33
  @done = false
35
34
  @job = nil
36
35
  @thread = nil
36
+ @config = options
37
37
  @strategy = options[:fetch]
38
38
  @reloader = options[:reloader] || proc { |&block| block.call }
39
39
  @job_logger = (options[:job_logger] || Sidekiq::JobLogger).new
40
- @retrier = Sidekiq::JobRetry.new
40
+ @retrier = Sidekiq::JobRetry.new(options)
41
41
  end
42
42
 
43
43
  def terminate(wait = false)
@@ -66,26 +66,26 @@ module Sidekiq
66
66
 
67
67
  def run
68
68
  process_one until @done
69
- @mgr.processor_stopped(self)
69
+ @callback.call(self)
70
70
  rescue Sidekiq::Shutdown
71
- @mgr.processor_stopped(self)
71
+ @callback.call(self)
72
72
  rescue Exception => ex
73
- @mgr.processor_died(self, ex)
73
+ @callback.call(self, ex)
74
74
  end
75
75
 
76
- def process_one
76
+ def process_one(&block)
77
77
  @job = fetch
78
78
  process(@job) if @job
79
79
  @job = nil
80
80
  end
81
81
 
82
82
  def get_one
83
- work = @strategy.retrieve_work
83
+ uow = @strategy.retrieve_work
84
84
  if @down
85
85
  logger.info { "Redis is online, #{::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - @down} sec downtime" }
86
86
  @down = nil
87
87
  end
88
- work
88
+ uow
89
89
  rescue Sidekiq::Shutdown
90
90
  rescue => ex
91
91
  handle_fetch_exception(ex)
@@ -130,10 +130,10 @@ module Sidekiq
130
130
  # Effectively this block denotes a "unit of work" to Rails.
131
131
  @reloader.call do
132
132
  klass = constantize(job_hash["class"])
133
- worker = klass.new
134
- worker.jid = job_hash["jid"]
135
- @retrier.local(worker, jobstr, queue) do
136
- yield worker
133
+ inst = klass.new
134
+ inst.jid = job_hash["jid"]
135
+ @retrier.local(inst, jobstr, queue) do
136
+ yield inst
137
137
  end
138
138
  end
139
139
  end
@@ -142,9 +142,9 @@ module Sidekiq
142
142
  end
143
143
  end
144
144
 
145
- def process(work)
146
- jobstr = work.job
147
- queue = work.queue_name
145
+ def process(uow)
146
+ jobstr = uow.job
147
+ queue = uow.queue_name
148
148
 
149
149
  # Treat malformed JSON as a special case: job goes straight to the morgue.
150
150
  job_hash = nil
@@ -154,14 +154,14 @@ module Sidekiq
154
154
  handle_exception(ex, {context: "Invalid JSON for job", jobstr: jobstr})
155
155
  # we can't notify because the job isn't a valid hash payload.
156
156
  DeadSet.new.kill(jobstr, notify_failure: false)
157
- return work.acknowledge
157
+ return uow.acknowledge
158
158
  end
159
159
 
160
160
  ack = false
161
161
  begin
162
- dispatch(job_hash, queue, jobstr) do |worker|
163
- Sidekiq.server_middleware.invoke(worker, job_hash, queue) do
164
- execute_job(worker, job_hash["args"])
162
+ dispatch(job_hash, queue, jobstr) do |inst|
163
+ @config.server_middleware.invoke(inst, job_hash, queue) do
164
+ execute_job(inst, job_hash["args"])
165
165
  end
166
166
  end
167
167
  ack = true
@@ -186,14 +186,14 @@ module Sidekiq
186
186
  if ack
187
187
  # We don't want a shutdown signal to interrupt job acknowledgment.
188
188
  Thread.handle_interrupt(Sidekiq::Shutdown => :never) do
189
- work.acknowledge
189
+ uow.acknowledge
190
190
  end
191
191
  end
192
192
  end
193
193
  end
194
194
 
195
- def execute_job(worker, cloned_args)
196
- worker.perform(*cloned_args)
195
+ def execute_job(inst, cloned_args)
196
+ inst.perform(*cloned_args)
197
197
  end
198
198
 
199
199
  # Ruby doesn't provide atomic counters out of the box so we'll
@@ -219,39 +219,39 @@ module Sidekiq
219
219
  end
220
220
 
221
221
  # jruby's Hash implementation is not threadsafe, so we wrap it in a mutex here
222
- class SharedWorkerState
222
+ class SharedWorkState
223
223
  def initialize
224
- @worker_state = {}
224
+ @work_state = {}
225
225
  @lock = Mutex.new
226
226
  end
227
227
 
228
228
  def set(tid, hash)
229
- @lock.synchronize { @worker_state[tid] = hash }
229
+ @lock.synchronize { @work_state[tid] = hash }
230
230
  end
231
231
 
232
232
  def delete(tid)
233
- @lock.synchronize { @worker_state.delete(tid) }
233
+ @lock.synchronize { @work_state.delete(tid) }
234
234
  end
235
235
 
236
236
  def dup
237
- @lock.synchronize { @worker_state.dup }
237
+ @lock.synchronize { @work_state.dup }
238
238
  end
239
239
 
240
240
  def size
241
- @lock.synchronize { @worker_state.size }
241
+ @lock.synchronize { @work_state.size }
242
242
  end
243
243
 
244
244
  def clear
245
- @lock.synchronize { @worker_state.clear }
245
+ @lock.synchronize { @work_state.clear }
246
246
  end
247
247
  end
248
248
 
249
249
  PROCESSED = Counter.new
250
250
  FAILURE = Counter.new
251
- WORKER_STATE = SharedWorkerState.new
251
+ WORK_STATE = SharedWorkState.new
252
252
 
253
253
  def stats(jobstr, queue)
254
- WORKER_STATE.set(tid, {queue: queue, payload: jobstr, run_at: Time.now.to_i})
254
+ WORK_STATE.set(tid, {queue: queue, payload: jobstr, run_at: Time.now.to_i})
255
255
 
256
256
  begin
257
257
  yield
@@ -259,7 +259,7 @@ module Sidekiq
259
259
  FAILURE.incr
260
260
  raise
261
261
  ensure
262
- WORKER_STATE.delete(tid)
262
+ WORK_STATE.delete(tid)
263
263
  PROCESSED.incr
264
264
  end
265
265
  end
data/lib/sidekiq/rails.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "sidekiq/worker"
3
+ require "sidekiq/job"
4
4
 
5
5
  module Sidekiq
6
6
  class Rails < ::Rails::Engine
@@ -33,28 +33,35 @@ module Sidekiq
33
33
  # end
34
34
  initializer "sidekiq.active_job_integration" do
35
35
  ActiveSupport.on_load(:active_job) do
36
- include ::Sidekiq::Worker::Options unless respond_to?(:sidekiq_options)
36
+ include ::Sidekiq::Job::Options unless respond_to?(:sidekiq_options)
37
37
  end
38
38
  end
39
39
 
40
40
  initializer "sidekiq.rails_logger" do
41
- Sidekiq.configure_server do |_|
42
- # This is the integration code necessary so that if code uses `Rails.logger.info "Hello"`,
41
+ Sidekiq.configure_server do |config|
42
+ # This is the integration code necessary so that if a job uses `Rails.logger.info "Hello"`,
43
43
  # it will appear in the Sidekiq console with all of the job context. See #5021 and
44
44
  # https://github.com/rails/rails/blob/b5f2b550f69a99336482739000c58e4e04e033aa/railties/lib/rails/commands/server/server_command.rb#L82-L84
45
- unless ::Rails.logger == ::Sidekiq.logger || ::ActiveSupport::Logger.logger_outputs_to?(::Rails.logger, $stdout)
46
- ::Rails.logger.extend(::ActiveSupport::Logger.broadcast(::Sidekiq.logger))
45
+ unless ::Rails.logger == config.logger || ::ActiveSupport::Logger.logger_outputs_to?(::Rails.logger, $stdout)
46
+ ::Rails.logger.extend(::ActiveSupport::Logger.broadcast(config.logger))
47
47
  end
48
48
  end
49
49
  end
50
50
 
51
+ config.before_configuration do
52
+ dep = ActiveSupport::Deprecation.new("7.0", "Sidekiq")
53
+ dep.deprecate_methods(Sidekiq.singleton_class,
54
+ default_worker_options: :default_job_options,
55
+ "default_worker_options=": :default_job_options=)
56
+ end
57
+
51
58
  # This hook happens after all initializers are run, just before returning
52
59
  # from config/environment.rb back to sidekiq/cli.rb.
53
60
  #
54
61
  # None of this matters on the client-side, only within the Sidekiq process itself.
55
62
  config.after_initialize do
56
- Sidekiq.configure_server do |_|
57
- Sidekiq.options[:reloader] = Sidekiq::Rails::Reloader.new
63
+ Sidekiq.configure_server do |config|
64
+ config[:reloader] = Sidekiq::Rails::Reloader.new
58
65
  end
59
66
  end
60
67
  end
@@ -0,0 +1,154 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "connection_pool"
4
+ require "redis_client"
5
+ require "redis_client/decorator"
6
+ require "uri"
7
+
8
+ module Sidekiq
9
+ class RedisClientAdapter
10
+ BaseError = RedisClient::Error
11
+ CommandError = RedisClient::CommandError
12
+
13
+ module CompatMethods
14
+ def info
15
+ @client.call("INFO") { |i| i.lines(chomp: true).map { |l| l.split(":", 2) }.select { |l| l.size == 2 }.to_h }
16
+ end
17
+
18
+ def evalsha(sha, keys, argv)
19
+ @client.call("EVALSHA", sha, keys.size, *keys, *argv)
20
+ end
21
+
22
+ def brpoplpush(*args)
23
+ @client.blocking_call(false, "BRPOPLPUSH", *args)
24
+ end
25
+
26
+ def brpop(*args)
27
+ @client.blocking_call(false, "BRPOP", *args)
28
+ end
29
+
30
+ def set(*args)
31
+ @client.call("SET", *args) { |r| r == "OK" }
32
+ end
33
+ ruby2_keywords :set if respond_to?(:ruby2_keywords, true)
34
+
35
+ def sismember(*args)
36
+ @client.call("SISMEMBER", *args) { |c| c > 0 }
37
+ end
38
+
39
+ def exists?(key)
40
+ @client.call("EXISTS", key) { |c| c > 0 }
41
+ end
42
+
43
+ private
44
+
45
+ def method_missing(*args, &block)
46
+ @client.call(*args, *block)
47
+ end
48
+ ruby2_keywords :method_missing if respond_to?(:ruby2_keywords, true)
49
+
50
+ def respond_to_missing?(name, include_private = false)
51
+ super # Appease the linter. We can't tell what is a valid command.
52
+ end
53
+ end
54
+
55
+ CompatClient = RedisClient::Decorator.create(CompatMethods)
56
+
57
+ class CompatClient
58
+ %i[scan sscan zscan hscan].each do |method|
59
+ alias_method :"#{method}_each", method
60
+ undef_method method
61
+ end
62
+
63
+ def disconnect!
64
+ @client.close
65
+ end
66
+
67
+ def connection
68
+ {id: @client.id}
69
+ end
70
+
71
+ def redis
72
+ self
73
+ end
74
+
75
+ def _client
76
+ @client
77
+ end
78
+
79
+ def message
80
+ yield nil, @queue.pop
81
+ end
82
+
83
+ # NB: this method does not return
84
+ def subscribe(chan)
85
+ @queue = ::Queue.new
86
+
87
+ pubsub = @client.pubsub
88
+ pubsub.call("subscribe", chan)
89
+
90
+ loop do
91
+ evt = pubsub.next_event
92
+ next if evt.nil?
93
+ next unless evt[0] == "message" && evt[1] == chan
94
+
95
+ (_, _, msg) = evt
96
+ @queue << msg
97
+ yield self
98
+ end
99
+ end
100
+ end
101
+
102
+ def initialize(options)
103
+ opts = client_opts(options)
104
+ @config = if opts.key?(:sentinels)
105
+ RedisClient.sentinel(**opts)
106
+ else
107
+ RedisClient.config(**opts)
108
+ end
109
+ end
110
+
111
+ def new_client
112
+ CompatClient.new(@config.new_client)
113
+ end
114
+
115
+ private
116
+
117
+ def client_opts(options)
118
+ opts = options.dup
119
+
120
+ if opts[:namespace]
121
+ Sidekiq.logger.error("Your Redis configuration uses the namespace '#{opts[:namespace]}' but this feature isn't supported by redis-client. " \
122
+ "Either use the redis adapter or remove the namespace.")
123
+ Kernel.exit(-127)
124
+ end
125
+
126
+ opts.delete(:size)
127
+ opts.delete(:pool_timeout)
128
+
129
+ if opts[:network_timeout]
130
+ opts[:timeout] = opts[:network_timeout]
131
+ opts.delete(:network_timeout)
132
+ end
133
+
134
+ if opts[:driver]
135
+ opts[:driver] = opts[:driver].to_sym
136
+ end
137
+
138
+ opts[:name] = opts.delete(:master_name) if opts.key?(:master_name)
139
+ opts[:role] = opts[:role].to_sym if opts.key?(:role)
140
+ opts.delete(:url) if opts.key?(:sentinels)
141
+
142
+ # Issue #3303, redis-rb will silently retry an operation.
143
+ # This can lead to duplicate jobs if Sidekiq::Client's LPUSH
144
+ # is performed twice but I believe this is much, much rarer
145
+ # than the reconnect silently fixing a problem; we keep it
146
+ # on by default.
147
+ opts[:reconnect_attempts] ||= 1
148
+
149
+ opts
150
+ end
151
+ end
152
+ end
153
+
154
+ Sidekiq::RedisConnection.adapter = Sidekiq::RedisClientAdapter
@@ -5,55 +5,20 @@ require "redis"
5
5
  require "uri"
6
6
 
7
7
  module Sidekiq
8
- class RedisConnection
9
- class << self
10
- def create(options = {})
11
- symbolized_options = options.transform_keys(&:to_sym)
12
-
13
- if !symbolized_options[:url] && (u = determine_redis_provider)
14
- symbolized_options[:url] = u
15
- end
16
-
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
28
-
29
- verify_sizing(size, Sidekiq.options[:concurrency]) if Sidekiq.server?
30
-
31
- pool_timeout = symbolized_options[:pool_timeout] || 1
32
- log_info(symbolized_options)
33
-
34
- ConnectionPool.new(timeout: pool_timeout, size: size) do
35
- build_client(symbolized_options)
36
- end
8
+ module RedisConnection
9
+ class RedisAdapter
10
+ BaseError = Redis::BaseError
11
+ CommandError = Redis::CommandError
12
+
13
+ def initialize(options)
14
+ warn("Usage of the 'redis' gem within Sidekiq itself is deprecated, Sidekiq 7.0 will only use the new, simpler 'redis-client' gem", caller) if ENV["SIDEKIQ_REDIS_CLIENT"] == "1"
15
+ @options = options
37
16
  end
38
17
 
39
- private
18
+ def new_client
19
+ namespace = @options[:namespace]
40
20
 
41
- # Sidekiq needs a lot of concurrent Redis connections.
42
- #
43
- # We need a connection for each Processor.
44
- # We need a connection for Pro's real-time change listener
45
- # We need a connection to various features to call Redis every few seconds:
46
- # - the process heartbeat.
47
- # - enterprise's leader election
48
- # - enterprise's cron support
49
- def verify_sizing(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)
51
- end
52
-
53
- def build_client(options)
54
- namespace = options[:namespace]
55
-
56
- client = Redis.new client_opts(options)
21
+ client = Redis.new client_opts(@options)
57
22
  if namespace
58
23
  begin
59
24
  require "redis/namespace"
@@ -68,6 +33,8 @@ module Sidekiq
68
33
  end
69
34
  end
70
35
 
36
+ private
37
+
71
38
  def client_opts(options)
72
39
  opts = options.dup
73
40
  if opts[:namespace]
@@ -90,6 +57,72 @@ module Sidekiq
90
57
 
91
58
  opts
92
59
  end
60
+ end
61
+
62
+ @adapter = RedisAdapter
63
+
64
+ class << self
65
+ attr_reader :adapter
66
+
67
+ # RedisConnection.adapter = :redis
68
+ # RedisConnection.adapter = :redis_client
69
+ def adapter=(adapter)
70
+ raise "no" if adapter == self
71
+ result = case adapter
72
+ when :redis
73
+ RedisAdapter
74
+ when Class
75
+ adapter
76
+ else
77
+ require "sidekiq/#{adapter}_adapter"
78
+ nil
79
+ end
80
+ @adapter = result if result
81
+ end
82
+
83
+ def create(options = {})
84
+ symbolized_options = options.transform_keys(&:to_sym)
85
+
86
+ if !symbolized_options[:url] && (u = determine_redis_provider)
87
+ symbolized_options[:url] = u
88
+ end
89
+
90
+ size = if symbolized_options[:size]
91
+ symbolized_options[:size]
92
+ elsif Sidekiq.server?
93
+ # Give ourselves plenty of connections. pool is lazy
94
+ # so we won't create them until we need them.
95
+ Sidekiq[:concurrency] + 5
96
+ elsif ENV["RAILS_MAX_THREADS"]
97
+ Integer(ENV["RAILS_MAX_THREADS"])
98
+ else
99
+ 5
100
+ end
101
+
102
+ verify_sizing(size, Sidekiq[:concurrency]) if Sidekiq.server?
103
+
104
+ pool_timeout = symbolized_options[:pool_timeout] || 1
105
+ log_info(symbolized_options)
106
+
107
+ redis_config = adapter.new(symbolized_options)
108
+ ConnectionPool.new(timeout: pool_timeout, size: size) do
109
+ redis_config.new_client
110
+ end
111
+ end
112
+
113
+ private
114
+
115
+ # Sidekiq needs many concurrent Redis connections.
116
+ #
117
+ # We need a connection for each Processor.
118
+ # We need a connection for Pro's real-time change listener
119
+ # We need a connection to various features to call Redis every few seconds:
120
+ # - the process heartbeat.
121
+ # - enterprise's leader election
122
+ # - enterprise's cron support
123
+ def verify_sizing(size, concurrency)
124
+ raise ArgumentError, "Your Redis connection pool is too small for Sidekiq. Your pool has #{size} connections but must have at least #{concurrency + 2}" if size < (concurrency + 2)
125
+ end
93
126
 
94
127
  def log_info(options)
95
128
  redacted = "REDACTED"
@@ -110,9 +143,9 @@ module Sidekiq
110
143
  sentinel[:password] = redacted if sentinel[:password]
111
144
  end
112
145
  if Sidekiq.server?
113
- Sidekiq.logger.info("Booting Sidekiq #{Sidekiq::VERSION} with redis options #{scrubbed_options}")
146
+ Sidekiq.logger.info("Booting Sidekiq #{Sidekiq::VERSION} with #{adapter.name} options #{scrubbed_options}")
114
147
  else
115
- Sidekiq.logger.debug("#{Sidekiq::NAME} client with redis options #{scrubbed_options}")
148
+ Sidekiq.logger.debug("#{Sidekiq::NAME} client with #{adapter.name} options #{scrubbed_options}")
116
149
  end
117
150
  end
118
151
 
@@ -0,0 +1,29 @@
1
+ require "forwardable"
2
+
3
+ module Sidekiq
4
+ class RingBuffer
5
+ include Enumerable
6
+ extend Forwardable
7
+ def_delegators :@buf, :[], :each, :size
8
+
9
+ def initialize(size, default = 0)
10
+ @size = size
11
+ @buf = Array.new(size, default)
12
+ @index = 0
13
+ end
14
+
15
+ def <<(element)
16
+ @buf[@index % @size] = element
17
+ @index += 1
18
+ element
19
+ end
20
+
21
+ def buffer
22
+ @buf
23
+ end
24
+
25
+ def reset(default = 0)
26
+ @buf.fill(default)
27
+ end
28
+ end
29
+ end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "sidekiq"
4
- require "sidekiq/util"
5
4
  require "sidekiq/api"
5
+ require "sidekiq/component"
6
6
 
7
7
  module Sidekiq
8
8
  module Scheduled
@@ -52,8 +52,8 @@ module Sidekiq
52
52
  @lua_zpopbyscore_sha = raw_conn.script(:load, LUA_ZPOPBYSCORE)
53
53
  end
54
54
 
55
- conn.evalsha(@lua_zpopbyscore_sha, keys: keys, argv: argv)
56
- rescue Redis::CommandError => e
55
+ conn.evalsha(@lua_zpopbyscore_sha, keys, argv)
56
+ rescue RedisConnection.adapter::CommandError => e
57
57
  raise unless e.message.start_with?("NOSCRIPT")
58
58
 
59
59
  @lua_zpopbyscore_sha = nil
@@ -67,12 +67,13 @@ module Sidekiq
67
67
  # just pops the job back onto its original queue so the
68
68
  # workers can pick it up like any other job.
69
69
  class Poller
70
- include Util
70
+ include Sidekiq::Component
71
71
 
72
72
  INITIAL_WAIT = 10
73
73
 
74
- def initialize
75
- @enq = (Sidekiq.options[:scheduled_enq] || Sidekiq::Scheduled::Enq).new
74
+ def initialize(options)
75
+ @config = options
76
+ @enq = (options[:scheduled_enq] || Sidekiq::Scheduled::Enq).new
76
77
  @sleeper = ConnectionPool::TimedStack.new
77
78
  @done = false
78
79
  @thread = nil
@@ -100,7 +101,7 @@ module Sidekiq
100
101
  enqueue
101
102
  wait
102
103
  end
103
- Sidekiq.logger.info("Scheduler exiting...")
104
+ logger.info("Scheduler exiting...")
104
105
  }
105
106
  end
106
107
 
@@ -171,14 +172,14 @@ module Sidekiq
171
172
  #
172
173
  # We only do this if poll_interval_average is unset (the default).
173
174
  def poll_interval_average
174
- Sidekiq.options[:poll_interval_average] ||= scaled_poll_interval
175
+ @config[:poll_interval_average] ||= scaled_poll_interval
175
176
  end
176
177
 
177
178
  # Calculates an average poll interval based on the number of known Sidekiq processes.
178
179
  # This minimizes a single point of failure by dispersing check-ins but without taxing
179
180
  # Redis if you run many Sidekiq processes.
180
181
  def scaled_poll_interval
181
- process_count * Sidekiq.options[:average_scheduled_poll_interval]
182
+ process_count * @config[:average_scheduled_poll_interval]
182
183
  end
183
184
 
184
185
  def process_count
@@ -197,7 +198,7 @@ module Sidekiq
197
198
  # to give time for the heartbeat to register (if the poll interval is going to be calculated by the number
198
199
  # of workers), and 5 random seconds to ensure they don't all hit Redis at the same time.
199
200
  total = 0
200
- total += INITIAL_WAIT unless Sidekiq.options[:poll_interval_average]
201
+ total += INITIAL_WAIT unless @config[:poll_interval_average]
201
202
  total += (5 * rand)
202
203
 
203
204
  @sleeper.pop(total)
@@ -4,7 +4,7 @@ require "sidekiq/testing"
4
4
 
5
5
  ##
6
6
  # The Sidekiq inline infrastructure overrides perform_async so that it
7
- # actually calls perform instead. This allows workers to be run inline in a
7
+ # actually calls perform instead. This allows jobs to be run inline in a
8
8
  # testing environment.
9
9
  #
10
10
  # This is similar to `Resque.inline = true` functionality.
@@ -15,8 +15,8 @@ require "sidekiq/testing"
15
15
  #
16
16
  # $external_variable = 0
17
17
  #
18
- # class ExternalWorker
19
- # include Sidekiq::Worker
18
+ # class ExternalJob
19
+ # include Sidekiq::Job
20
20
  #
21
21
  # def perform
22
22
  # $external_variable = 1
@@ -24,7 +24,7 @@ require "sidekiq/testing"
24
24
  # end
25
25
  #
26
26
  # assert_equal 0, $external_variable
27
- # ExternalWorker.perform_async
27
+ # ExternalJob.perform_async
28
28
  # assert_equal 1, $external_variable
29
29
  #
30
30
  Sidekiq::Testing.inline!