Skip to content

Commit

Permalink
Merge pull request #9484 from joshcooper/splaylimit_daemon
Browse files Browse the repository at this point in the history
(PUP-12061) Allow splay and splaylimit to be modified in puppet.conf
  • Loading branch information
mhashizume authored Sep 30, 2024
2 parents d0ec909 + 15bc22b commit c58db7a
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 5 deletions.
14 changes: 13 additions & 1 deletion lib/puppet/daemon.rb
Original file line number Diff line number Diff line change
Expand Up @@ -157,14 +157,25 @@ def remove_pidfile

# Loop forever running events - or, at least, until we exit.
def run_event_loop
agent_run = Puppet::Scheduler.create_job(Puppet[:runinterval], Puppet[:splay], Puppet[:splaylimit]) do
splaylimit = Puppet[:splay] ? Puppet[:splaylimit] : 0

agent_run = Puppet::Scheduler.create_job(Puppet[:runinterval], true, splaylimit) do |job|
if job.splay != 0
Puppet.info "Running agent every #{job.run_interval} seconds with splay #{job.splay} of #{job.splay_limit} seconds"
else
Puppet.info "Running agent every #{job.run_interval} seconds"
end

# Splay for the daemon is handled in the scheduler
agent.run(:splay => false)
end

reparse_run = Puppet::Scheduler.create_job(Puppet[:filetimeout]) do
Puppet.settings.reparse_config_files
agent_run.run_interval = Puppet[:runinterval]
# Puppet[:splaylimit] defaults to Puppet[:runinterval] so if runinterval
# changes, but splaylimit doesn't, we'll still recalculate splay
agent_run.splay_limit = Puppet[:splay] ? Puppet[:splaylimit] : 0
if Puppet[:filetimeout] == 0
reparse_run.disable
else
Expand All @@ -181,6 +192,7 @@ def run_event_loop

reparse_run.disable if Puppet[:filetimeout] == 0

# these are added in a different order than they are defined
@scheduler.run_loop([reparse_run, agent_run, signal_loop])
end
end
17 changes: 14 additions & 3 deletions lib/puppet/scheduler/splay_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

module Puppet::Scheduler
class SplayJob < Job
attr_reader :splay
attr_reader :splay, :splay_limit

def initialize(run_interval, splay_limit, &block)
@splay = calculate_splay(splay_limit)
@splay, @splay_limit = calculate_splay(splay_limit)
super(run_interval, &block)
end

Expand All @@ -25,10 +25,21 @@ def ready?(time)
end
end

# Recalculates splay.
#
# @param splay_limit [Integer] the maximum time (in seconds) to delay before an agent's first run.
# @return @splay [Integer] a random integer less than or equal to the splay limit that represents the seconds to
# delay before next agent run.
def splay_limit=(splay_limit)
if @splay_limit != splay_limit
@splay, @splay_limit = calculate_splay(splay_limit)
end
end

private

def calculate_splay(limit)
rand(limit + 1)
[rand(limit + 1), limit]
end
end
end
83 changes: 82 additions & 1 deletion spec/unit/daemon_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ def run_loop(jobs)
end

describe "when starting" do
let(:reparse_run) { scheduler.jobs[0] }
let(:agent_run) { scheduler.jobs[1] }

before do
allow(daemon).to receive(:set_signal_traps)
end
Expand All @@ -77,7 +80,85 @@ def run_loop(jobs)
it "disables the reparse of configs if the filetimeout is 0" do
Puppet[:filetimeout] = 0
daemon.start
expect(scheduler.jobs[0]).not_to be_enabled
expect(reparse_run).not_to be_enabled
end

it "does not splay the agent run by default" do
daemon.start
expect(agent_run.splay).to eq(0)
end

describe "and calculating splay" do
before do
# Set file timeout so the daemon reparses
Puppet[:filetimeout] = 1
Puppet[:splay] = true
end

it "recalculates when splaylimit changes" do
daemon.start

Puppet[:splaylimit] = 60
init_splay = agent_run.splay
next_splay = init_splay + 1
allow(agent_run).to receive(:rand).and_return(next_splay)
reparse_run.run(Time.now)

expect(agent_run.splay).to eq(next_splay)
end

it "does not change splay if splaylimit is unmodified" do
daemon.start

init_splay = agent_run.splay
reparse_run.run(Time.now)

expect(agent_run.splay).to eq(init_splay)
end

it "recalculates when splay is enabled later" do
Puppet[:splay] = false
daemon.start

Puppet[:splay] = true
allow(agent_run).to receive(:rand).and_return(999)
reparse_run.run(Time.now)

expect(agent_run.splay).to eq(999)
end

it "sets splay to 0 when splay is disabled" do
daemon.start

Puppet[:splay] = false
reparse_run.run(Time.now)

expect(agent_run.splay).to eq(0)
end

it "recalculates splay when runinterval is decreased" do
Puppet[:runinterval] = 60
daemon.start

Puppet[:runinterval] = Puppet[:runinterval] - 30
new_splay = agent_run.splay + 1
allow(agent_run).to receive(:rand).and_return(new_splay)
reparse_run.run(Time.now)

expect(agent_run.splay).to eq(new_splay)
end

it "recalculates splay when runinterval is increased" do
Puppet[:runinterval] = 60
daemon.start

Puppet[:runinterval] = Puppet[:runinterval] + 30
new_splay = agent_run.splay - 1
allow(agent_run).to receive(:rand).and_return(new_splay)
reparse_run.run(Time.now)

expect(agent_run.splay).to eq(new_splay)
end
end
end

Expand Down
17 changes: 17 additions & 0 deletions spec/unit/scheduler/splay_job_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,21 @@
expect(job).to receive(:splay).and_return(6)
expect(job.ready?(start_time)).not_to be
end

it "does not apply a splay if the splaylimit is unchanged" do
old_splay = job.splay
job.splay_limit = splay_limit
expect(job.splay).to eq(old_splay)
end

it "applies a splay if the splaylimit is changed" do
new_splay = 999
allow(job).to receive(:rand).and_return(new_splay)
job.splay_limit = splay_limit + 1
expect(job.splay).to eq(new_splay)
end

it "returns the splay_limit" do
expect(job.splay_limit).to eq(splay_limit)
end
end

0 comments on commit c58db7a

Please sign in to comment.