1
0
Fork 0
mirror of https://github.com/mperham/sidekiq.git synced 2022-11-09 13:52:34 -05:00

make the average global poller delay configurable

This commit is contained in:
Lance Ivy 2015-04-24 08:35:47 -07:00
parent 1825f28058
commit 4255aaf0c2
3 changed files with 61 additions and 9 deletions

View file

@ -20,6 +20,8 @@ module Sidekiq
require: '.', require: '.',
environment: nil, environment: nil,
timeout: 8, timeout: 8,
poll_interval_average: nil,
global_poll_interval_average: 15,
error_handlers: [], error_handlers: [],
lifecycle_events: { lifecycle_events: {
startup: [], startup: [],
@ -127,9 +129,13 @@ module Sidekiq
Sidekiq::Logging.logger = log Sidekiq::Logging.logger = log
end end
# When set, overrides Sidekiq.options[:global_poll_interval_average] and sets the
# average interval that this process will delay before checking for scheduled jobs
# or job retries that are ready to run.
#
# See sidekiq/scheduled.rb for an in-depth explanation of this value # See sidekiq/scheduled.rb for an in-depth explanation of this value
def self.poll_interval=(interval) def self.poll_interval=(interval)
self.options[:poll_interval] = interval self.options[:poll_interval_average] = interval
end end
# Register a proc to handle any error which occurs within the Sidekiq process. # Register a proc to handle any error which occurs within the Sidekiq process.

View file

@ -68,7 +68,7 @@ module Sidekiq
# Calculates a random interval that is ±50% the desired average. # Calculates a random interval that is ±50% the desired average.
def random_poll_interval def random_poll_interval
poll_interval * rand + poll_interval.to_f / 2 poll_interval_average * rand + poll_interval_average.to_f / 2
end end
# We do our best to tune poll_interval to the size of the active Sidekiq # We do our best to tune poll_interval to the size of the active Sidekiq
@ -84,13 +84,17 @@ module Sidekiq
# the same time: the thundering herd problem. # the same time: the thundering herd problem.
# #
# We only do this if poll_interval is unset (the default). # We only do this if poll_interval is unset (the default).
def poll_interval def poll_interval_average
Sidekiq.options[:poll_interval] ||= begin Sidekiq.options[:poll_interval_average] ||= scaled_poll_interval
ps = Sidekiq::ProcessSet.new end
pcount = ps.size
pcount = 1 if pcount == 0 # Calculates an average poll interval based on the number of known Sidekiq processes.
pcount * 15 # This minimizes a single point of failure by dispersing check-ins but without taxing
end # Redis if you run many Sidekiq processes.
def scaled_poll_interval
pcount = Sidekiq::ProcessSet.new.size
pcount = 1 if pcount == 0
pcount * Sidekiq.options[:global_poll_interval_average]
end end
def initial_wait def initial_wait

View file

@ -82,5 +82,47 @@ class TestScheduled < Sidekiq::Test
assert_equal 1, @scheduled.size assert_equal 1, @scheduled.size
end end
end end
def with_sidekiq_option(name, value)
_original, Sidekiq.options[name] = Sidekiq.options[name], value
begin
yield
ensure
Sidekiq.options[name] = _original
end
end
it 'generates random intervals that target a configured average' do
with_sidekiq_option(:poll_interval_average, 10) do
i = 500
intervals = i.times.map{ @poller.send(:random_poll_interval) }
assert intervals.all?{|i| i >= 5}
assert intervals.all?{|i| i <= 15}
assert_in_delta 10, intervals.reduce(&:+).to_f / i, 0.5
end
end
it 'calculates an average poll interval based on the number of known Sidekiq processes' do
with_sidekiq_option(:global_poll_interval_average, 10) do
begin
3.times do |i|
Sidekiq.redis do |conn|
conn.sadd("processes", "process-#{i}")
conn.hset("process-#{i}", "info", nil)
end
end
assert_equal 30, @poller.send(:scaled_poll_interval)
ensure
3.times do |i|
Sidekiq.redis do |conn|
conn.srem("processes", "process-#{i}")
conn.del("process-#{i}")
end
end
end
end
end
end end
end end