sidekiq 6.3.1 → 7.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +285 -11
  3. data/LICENSE.txt +9 -0
  4. data/README.md +47 -34
  5. data/bin/sidekiq +4 -9
  6. data/bin/sidekiqload +207 -117
  7. data/bin/sidekiqmon +4 -1
  8. data/lib/generators/sidekiq/job_generator.rb +57 -0
  9. data/lib/generators/sidekiq/templates/{worker.rb.erb → job.rb.erb} +2 -2
  10. data/lib/generators/sidekiq/templates/{worker_spec.rb.erb → job_spec.rb.erb} +1 -1
  11. data/lib/generators/sidekiq/templates/{worker_test.rb.erb → job_test.rb.erb} +1 -1
  12. data/lib/sidekiq/api.rb +333 -190
  13. data/lib/sidekiq/capsule.rb +127 -0
  14. data/lib/sidekiq/cli.rb +86 -80
  15. data/lib/sidekiq/client.rb +104 -95
  16. data/lib/sidekiq/{util.rb → component.rb} +14 -41
  17. data/lib/sidekiq/config.rb +282 -0
  18. data/lib/sidekiq/deploy.rb +62 -0
  19. data/lib/sidekiq/embedded.rb +61 -0
  20. data/lib/sidekiq/fetch.rb +23 -24
  21. data/lib/sidekiq/job.rb +371 -10
  22. data/lib/sidekiq/job_logger.rb +16 -28
  23. data/lib/sidekiq/job_retry.rb +99 -58
  24. data/lib/sidekiq/job_util.rb +107 -0
  25. data/lib/sidekiq/launcher.rb +103 -95
  26. data/lib/sidekiq/logger.rb +9 -44
  27. data/lib/sidekiq/manager.rb +40 -41
  28. data/lib/sidekiq/metrics/query.rb +153 -0
  29. data/lib/sidekiq/metrics/shared.rb +95 -0
  30. data/lib/sidekiq/metrics/tracking.rb +136 -0
  31. data/lib/sidekiq/middleware/chain.rb +96 -51
  32. data/lib/sidekiq/middleware/current_attributes.rb +59 -16
  33. data/lib/sidekiq/middleware/i18n.rb +6 -4
  34. data/lib/sidekiq/middleware/modules.rb +21 -0
  35. data/lib/sidekiq/monitor.rb +17 -4
  36. data/lib/sidekiq/paginator.rb +17 -9
  37. data/lib/sidekiq/processor.rb +81 -80
  38. data/lib/sidekiq/rails.rb +21 -14
  39. data/lib/sidekiq/redis_client_adapter.rb +95 -0
  40. data/lib/sidekiq/redis_connection.rb +14 -82
  41. data/lib/sidekiq/ring_buffer.rb +29 -0
  42. data/lib/sidekiq/scheduled.rb +76 -38
  43. data/lib/sidekiq/testing/inline.rb +4 -4
  44. data/lib/sidekiq/testing.rb +42 -69
  45. data/lib/sidekiq/transaction_aware_client.rb +44 -0
  46. data/lib/sidekiq/version.rb +2 -1
  47. data/lib/sidekiq/web/action.rb +3 -3
  48. data/lib/sidekiq/web/application.rb +95 -11
  49. data/lib/sidekiq/web/csrf_protection.rb +4 -4
  50. data/lib/sidekiq/web/helpers.rb +58 -30
  51. data/lib/sidekiq/web.rb +22 -17
  52. data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
  53. data/lib/sidekiq.rb +85 -202
  54. data/sidekiq.gemspec +12 -10
  55. data/web/assets/javascripts/application.js +77 -26
  56. data/web/assets/javascripts/base-charts.js +106 -0
  57. data/web/assets/javascripts/chart.min.js +13 -0
  58. data/web/assets/javascripts/chartjs-plugin-annotation.min.js +7 -0
  59. data/web/assets/javascripts/dashboard-charts.js +168 -0
  60. data/web/assets/javascripts/dashboard.js +3 -240
  61. data/web/assets/javascripts/metrics.js +264 -0
  62. data/web/assets/stylesheets/application-dark.css +17 -17
  63. data/web/assets/stylesheets/application-rtl.css +2 -91
  64. data/web/assets/stylesheets/application.css +69 -302
  65. data/web/locales/ar.yml +70 -70
  66. data/web/locales/cs.yml +62 -62
  67. data/web/locales/da.yml +60 -53
  68. data/web/locales/de.yml +65 -65
  69. data/web/locales/el.yml +43 -24
  70. data/web/locales/en.yml +84 -69
  71. data/web/locales/es.yml +68 -68
  72. data/web/locales/fa.yml +65 -65
  73. data/web/locales/fr.yml +81 -67
  74. data/web/locales/gd.yml +99 -0
  75. data/web/locales/he.yml +65 -64
  76. data/web/locales/hi.yml +59 -59
  77. data/web/locales/it.yml +53 -53
  78. data/web/locales/ja.yml +73 -68
  79. data/web/locales/ko.yml +52 -52
  80. data/web/locales/lt.yml +66 -66
  81. data/web/locales/nb.yml +61 -61
  82. data/web/locales/nl.yml +52 -52
  83. data/web/locales/pl.yml +45 -45
  84. data/web/locales/pt-br.yml +83 -55
  85. data/web/locales/pt.yml +51 -51
  86. data/web/locales/ru.yml +67 -66
  87. data/web/locales/sv.yml +53 -53
  88. data/web/locales/ta.yml +60 -60
  89. data/web/locales/uk.yml +62 -61
  90. data/web/locales/ur.yml +64 -64
  91. data/web/locales/vi.yml +67 -67
  92. data/web/locales/zh-cn.yml +43 -16
  93. data/web/locales/zh-tw.yml +42 -8
  94. data/web/views/_footer.erb +5 -2
  95. data/web/views/_job_info.erb +18 -2
  96. data/web/views/_metrics_period_select.erb +12 -0
  97. data/web/views/_nav.erb +1 -1
  98. data/web/views/_paging.erb +2 -0
  99. data/web/views/_poll_link.erb +1 -1
  100. data/web/views/_summary.erb +1 -1
  101. data/web/views/busy.erb +44 -28
  102. data/web/views/dashboard.erb +36 -4
  103. data/web/views/filtering.erb +7 -0
  104. data/web/views/metrics.erb +82 -0
  105. data/web/views/metrics_for_job.erb +68 -0
  106. data/web/views/morgue.erb +5 -9
  107. data/web/views/queue.erb +15 -15
  108. data/web/views/queues.erb +3 -1
  109. data/web/views/retries.erb +5 -9
  110. data/web/views/scheduled.erb +12 -13
  111. metadata +62 -31
  112. data/LICENSE +0 -9
  113. data/lib/generators/sidekiq/worker_generator.rb +0 -57
  114. data/lib/sidekiq/delay.rb +0 -41
  115. data/lib/sidekiq/exception_handler.rb +0 -27
  116. data/lib/sidekiq/extensions/action_mailer.rb +0 -48
  117. data/lib/sidekiq/extensions/active_record.rb +0 -43
  118. data/lib/sidekiq/extensions/class_methods.rb +0 -43
  119. data/lib/sidekiq/extensions/generic_proxy.rb +0 -33
  120. data/lib/sidekiq/worker.rb +0 -311
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+ require "redis_client"
5
+ require "redis_client/decorator"
6
+
7
+ module Sidekiq
8
+ class RedisClientAdapter
9
+ BaseError = RedisClient::Error
10
+ CommandError = RedisClient::CommandError
11
+
12
+ # You can add/remove items or clear the whole thing if you don't want deprecation warnings.
13
+ DEPRECATED_COMMANDS = %i[rpoplpush zrangebyscore zrevrange zrevrangebyscore getset hmset setex setnx].to_set
14
+
15
+ module CompatMethods
16
+ def info
17
+ @client.call("INFO") { |i| i.lines(chomp: true).map { |l| l.split(":", 2) }.select { |l| l.size == 2 }.to_h }
18
+ end
19
+
20
+ def evalsha(sha, keys, argv)
21
+ @client.call("EVALSHA", sha, keys.size, *keys, *argv)
22
+ end
23
+
24
+ private
25
+
26
+ # this allows us to use methods like `conn.hmset(...)` instead of having to use
27
+ # redis-client's native `conn.call("hmset", ...)`
28
+ def method_missing(*args, &block)
29
+ warn("[sidekiq#5788] Redis has deprecated the `#{args.first}`command, called at #{caller(1..1)}") if DEPRECATED_COMMANDS.include?(args.first)
30
+ @client.call(*args, *block)
31
+ end
32
+ ruby2_keywords :method_missing if respond_to?(:ruby2_keywords, true)
33
+
34
+ def respond_to_missing?(name, include_private = false)
35
+ super # Appease the linter. We can't tell what is a valid command.
36
+ end
37
+ end
38
+
39
+ CompatClient = RedisClient::Decorator.create(CompatMethods)
40
+
41
+ class CompatClient
42
+ def config
43
+ @client.config
44
+ end
45
+ end
46
+
47
+ def initialize(options)
48
+ opts = client_opts(options)
49
+ @config = if opts.key?(:sentinels)
50
+ RedisClient.sentinel(**opts)
51
+ else
52
+ RedisClient.config(**opts)
53
+ end
54
+ end
55
+
56
+ def new_client
57
+ CompatClient.new(@config.new_client)
58
+ end
59
+
60
+ private
61
+
62
+ def client_opts(options)
63
+ opts = options.dup
64
+
65
+ if opts[:namespace]
66
+ raise ArgumentError, "Your Redis configuration uses the namespace '#{opts[:namespace]}' but this feature is no longer supported in Sidekiq 7+. See https://github.com/sidekiq/sidekiq/blob/main/docs/7.0-Upgrade.md#redis-namespace."
67
+ end
68
+
69
+ opts.delete(:size)
70
+ opts.delete(:pool_timeout)
71
+
72
+ if opts[:network_timeout]
73
+ opts[:timeout] = opts[:network_timeout]
74
+ opts.delete(:network_timeout)
75
+ end
76
+
77
+ if opts[:driver]
78
+ opts[:driver] = opts[:driver].to_sym
79
+ end
80
+
81
+ opts[:name] = opts.delete(:master_name) if opts.key?(:master_name)
82
+ opts[:role] = opts[:role].to_sym if opts.key?(:role)
83
+ opts.delete(:url) if opts.key?(:sentinels)
84
+
85
+ # Issue #3303, redis-rb will silently retry an operation.
86
+ # This can lead to duplicate jobs if Sidekiq::Client's LPUSH
87
+ # is performed twice but I believe this is much, much rarer
88
+ # than the reconnect silently fixing a problem; we keep it
89
+ # on by default.
90
+ opts[:reconnect_attempts] ||= 1
91
+
92
+ opts
93
+ end
94
+ end
95
+ end
@@ -1,97 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "connection_pool"
4
- require "redis"
5
4
  require "uri"
5
+ require "sidekiq/redis_client_adapter"
6
6
 
7
7
  module Sidekiq
8
- class RedisConnection
8
+ module RedisConnection
9
9
  class << self
10
10
  def create(options = {})
11
11
  symbolized_options = options.transform_keys(&:to_sym)
12
+ symbolized_options[:url] ||= determine_redis_provider
12
13
 
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
14
+ logger = symbolized_options.delete(:logger)
15
+ logger&.info { "Sidekiq #{Sidekiq::VERSION} connecting to Redis with options #{scrub(symbolized_options)}" }
28
16
 
29
- verify_sizing(size, Sidekiq.options[:concurrency]) if Sidekiq.server?
17
+ raise "Sidekiq 7+ does not support Redis protocol 2" if symbolized_options[:protocol] == 2
18
+ size = symbolized_options.delete(:size) || 5
19
+ pool_timeout = symbolized_options.delete(:pool_timeout) || 1
20
+ pool_name = symbolized_options.delete(:pool_name)
30
21
 
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)
22
+ redis_config = Sidekiq::RedisClientAdapter.new(symbolized_options)
23
+ ConnectionPool.new(timeout: pool_timeout, size: size, name: pool_name) do
24
+ redis_config.new_client
36
25
  end
37
26
  end
38
27
 
39
28
  private
40
29
 
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)
57
- if namespace
58
- begin
59
- require "redis/namespace"
60
- Redis::Namespace.new(namespace, redis: client)
61
- rescue LoadError
62
- Sidekiq.logger.error("Your Redis configuration uses the namespace '#{namespace}' but the redis-namespace gem is not included in the Gemfile." \
63
- "Add the gem to your Gemfile to continue using a namespace. Otherwise, remove the namespace parameter.")
64
- exit(-127)
65
- end
66
- else
67
- client
68
- end
69
- end
70
-
71
- def client_opts(options)
72
- opts = options.dup
73
- if opts[:namespace]
74
- opts.delete(:namespace)
75
- end
76
-
77
- if opts[:network_timeout]
78
- opts[:timeout] = opts[:network_timeout]
79
- opts.delete(:network_timeout)
80
- end
81
-
82
- opts[:driver] ||= Redis::Connection.drivers.last || "ruby"
83
-
84
- # Issue #3303, redis-rb will silently retry an operation.
85
- # This can lead to duplicate jobs if Sidekiq::Client's LPUSH
86
- # is performed twice but I believe this is much, much rarer
87
- # than the reconnect silently fixing a problem; we keep it
88
- # on by default.
89
- opts[:reconnect_attempts] ||= 1
90
-
91
- opts
92
- end
93
-
94
- def log_info(options)
30
+ def scrub(options)
95
31
  redacted = "REDACTED"
96
32
 
97
33
  # Deep clone so we can muck with these options all we want and exclude
@@ -109,11 +45,7 @@ module Sidekiq
109
45
  scrubbed_options[:sentinels]&.each do |sentinel|
110
46
  sentinel[:password] = redacted if sentinel[:password]
111
47
  end
112
- if Sidekiq.server?
113
- Sidekiq.logger.info("Booting Sidekiq #{Sidekiq::VERSION} with redis options #{scrubbed_options}")
114
- else
115
- Sidekiq.logger.debug("#{Sidekiq::NAME} client with redis options #{scrubbed_options}")
116
- end
48
+ scrubbed_options
117
49
  end
118
50
 
119
51
  def determine_redis_provider
@@ -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,51 +1,61 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "sidekiq"
4
- require "sidekiq/util"
5
- require "sidekiq/api"
4
+ require "sidekiq/component"
6
5
 
7
6
  module Sidekiq
8
7
  module Scheduled
9
8
  SETS = %w[retry schedule]
10
9
 
11
10
  class Enq
11
+ include Sidekiq::Component
12
+
12
13
  LUA_ZPOPBYSCORE = <<~LUA
13
14
  local key, now = KEYS[1], ARGV[1]
14
- local jobs = redis.call("zrangebyscore", key, "-inf", now, "limit", 0, 1)
15
+ local jobs = redis.call("zrange", key, "-inf", now, "byscore", "limit", 0, 1)
15
16
  if jobs[1] then
16
17
  redis.call("zrem", key, jobs[1])
17
18
  return jobs[1]
18
19
  end
19
20
  LUA
20
21
 
21
- def initialize
22
+ def initialize(container)
23
+ @config = container
24
+ @client = Sidekiq::Client.new(config: container)
25
+ @done = false
22
26
  @lua_zpopbyscore_sha = nil
23
27
  end
24
28
 
25
- def enqueue_jobs(now = Time.now.to_f.to_s, sorted_sets = SETS)
29
+ def enqueue_jobs(sorted_sets = SETS)
26
30
  # A job's "score" in Redis is the time at which it should be processed.
27
31
  # Just check Redis for the set of jobs with a timestamp before now.
28
- Sidekiq.redis do |conn|
32
+ redis do |conn|
29
33
  sorted_sets.each do |sorted_set|
30
34
  # Get next item in the queue with score (time to execute) <= now.
31
35
  # We need to go through the list one at a time to reduce the risk of something
32
36
  # going wrong between the time jobs are popped from the scheduled queue and when
33
37
  # they are pushed onto a work queue and losing the jobs.
34
- while (job = zpopbyscore(conn, keys: [sorted_set], argv: [now]))
35
- Sidekiq::Client.push(Sidekiq.load_json(job))
36
- Sidekiq.logger.debug { "enqueued #{sorted_set}: #{job}" }
38
+ while !@done && (job = zpopbyscore(conn, keys: [sorted_set], argv: [Time.now.to_f.to_s]))
39
+ @client.push(Sidekiq.load_json(job))
40
+ logger.debug { "enqueued #{sorted_set}: #{job}" }
37
41
  end
38
42
  end
39
43
  end
40
44
  end
41
45
 
46
+ def terminate
47
+ @done = true
48
+ end
49
+
42
50
  private
43
51
 
44
52
  def zpopbyscore(conn, keys: nil, argv: nil)
45
- @lua_zpopbyscore_sha = conn.script(:load, LUA_ZPOPBYSCORE) if @lua_zpopbyscore_sha.nil?
53
+ if @lua_zpopbyscore_sha.nil?
54
+ @lua_zpopbyscore_sha = conn.script(:load, LUA_ZPOPBYSCORE)
55
+ end
46
56
 
47
- conn.evalsha(@lua_zpopbyscore_sha, keys: keys, argv: argv)
48
- rescue Redis::CommandError => e
57
+ conn.call("EVALSHA", @lua_zpopbyscore_sha, keys.size, *keys, *argv)
58
+ rescue RedisClient::CommandError => e
49
59
  raise unless e.message.start_with?("NOSCRIPT")
50
60
 
51
61
  @lua_zpopbyscore_sha = nil
@@ -59,12 +69,13 @@ module Sidekiq
59
69
  # just pops the job back onto its original queue so the
60
70
  # workers can pick it up like any other job.
61
71
  class Poller
62
- include Util
72
+ include Sidekiq::Component
63
73
 
64
74
  INITIAL_WAIT = 10
65
75
 
66
- def initialize
67
- @enq = (Sidekiq.options[:scheduled_enq] || Sidekiq::Scheduled::Enq).new
76
+ def initialize(config)
77
+ @config = config
78
+ @enq = (config[:scheduled_enq] || Sidekiq::Scheduled::Enq).new(config)
68
79
  @sleeper = ConnectionPool::TimedStack.new
69
80
  @done = false
70
81
  @thread = nil
@@ -74,12 +85,10 @@ module Sidekiq
74
85
  # Shut down this instance, will pause until the thread is dead.
75
86
  def terminate
76
87
  @done = true
77
- if @thread
78
- t = @thread
79
- @thread = nil
80
- @sleeper << 0
81
- t.value
82
- end
88
+ @enq.terminate
89
+
90
+ @sleeper << 0
91
+ @thread&.value
83
92
  end
84
93
 
85
94
  def start
@@ -90,7 +99,7 @@ module Sidekiq
90
99
  enqueue
91
100
  wait
92
101
  end
93
- Sidekiq.logger.info("Scheduler exiting...")
102
+ logger.info("Scheduler exiting...")
94
103
  }
95
104
  end
96
105
 
@@ -137,13 +146,16 @@ module Sidekiq
137
146
  # As we run more processes, the scheduling interval average will approach an even spread
138
147
  # between 0 and poll interval so we don't need this artifical boost.
139
148
  #
140
- if process_count < 10
149
+ count = process_count
150
+ interval = poll_interval_average(count)
151
+
152
+ if count < 10
141
153
  # For small clusters, calculate a random interval that is ±50% the desired average.
142
- poll_interval_average * rand + poll_interval_average.to_f / 2
154
+ interval * rand + interval.to_f / 2
143
155
  else
144
156
  # With 10+ processes, we should have enough randomness to get decent polling
145
157
  # across the entire timespan
146
- poll_interval_average * rand
158
+ interval * rand
147
159
  end
148
160
  end
149
161
 
@@ -160,38 +172,64 @@ module Sidekiq
160
172
  # the same time: the thundering herd problem.
161
173
  #
162
174
  # We only do this if poll_interval_average is unset (the default).
163
- def poll_interval_average
164
- Sidekiq.options[:poll_interval_average] ||= scaled_poll_interval
175
+ def poll_interval_average(count)
176
+ @config[:poll_interval_average] || scaled_poll_interval(count)
165
177
  end
166
178
 
167
179
  # Calculates an average poll interval based on the number of known Sidekiq processes.
168
180
  # This minimizes a single point of failure by dispersing check-ins but without taxing
169
181
  # Redis if you run many Sidekiq processes.
170
- def scaled_poll_interval
171
- process_count * Sidekiq.options[:average_scheduled_poll_interval]
182
+ def scaled_poll_interval(process_count)
183
+ process_count * @config[:average_scheduled_poll_interval]
172
184
  end
173
185
 
174
186
  def process_count
175
- # The work buried within Sidekiq::ProcessSet#cleanup can be
176
- # expensive at scale. Cut it down by 90% with this counter.
177
- # NB: This method is only called by the scheduler thread so we
178
- # don't need to worry about the thread safety of +=.
179
- pcount = Sidekiq::ProcessSet.new(@count_calls % 10 == 0).size
187
+ pcount = Sidekiq.redis { |conn| conn.scard("processes") }
180
188
  pcount = 1 if pcount == 0
181
- @count_calls += 1
182
189
  pcount
183
190
  end
184
191
 
192
+ # A copy of Sidekiq::ProcessSet#cleanup because server
193
+ # should never depend on sidekiq/api.
194
+ def cleanup
195
+ # dont run cleanup more than once per minute
196
+ return 0 unless redis { |conn| conn.set("process_cleanup", "1", nx: true, ex: 60) }
197
+
198
+ count = 0
199
+ redis do |conn|
200
+ procs = conn.sscan("processes").to_a
201
+ heartbeats = conn.pipelined { |pipeline|
202
+ procs.each do |key|
203
+ pipeline.hget(key, "info")
204
+ end
205
+ }
206
+
207
+ # the hash named key has an expiry of 60 seconds.
208
+ # if it's not found, that means the process has not reported
209
+ # in to Redis and probably died.
210
+ to_prune = procs.select.with_index { |proc, i|
211
+ heartbeats[i].nil?
212
+ }
213
+ count = conn.srem("processes", to_prune) unless to_prune.empty?
214
+ end
215
+ count
216
+ end
217
+
185
218
  def initial_wait
186
- # Have all processes sleep between 5-15 seconds. 10 seconds
187
- # to give time for the heartbeat to register (if the poll interval is going to be calculated by the number
219
+ # Have all processes sleep between 5-15 seconds. 10 seconds to give time for
220
+ # the heartbeat to register (if the poll interval is going to be calculated by the number
188
221
  # of workers), and 5 random seconds to ensure they don't all hit Redis at the same time.
189
222
  total = 0
190
- total += INITIAL_WAIT unless Sidekiq.options[:poll_interval_average]
223
+ total += INITIAL_WAIT unless @config[:poll_interval_average]
191
224
  total += (5 * rand)
192
225
 
193
226
  @sleeper.pop(total)
194
227
  rescue Timeout::Error
228
+ ensure
229
+ # periodically clean out the `processes` set in Redis which can collect
230
+ # references to dead processes over time. The process count affects how
231
+ # often we scan for scheduled jobs.
232
+ cleanup
195
233
  end
196
234
  end
197
235
  end
@@ -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!