You want to stop all your cronjobs running at the same time.
class staggered_cron {
$minute = fqdn_rand(59)
notify { "I got ${minute}": }
cron { 'freshen_cache':
command => '/usr/local/sbin/freshen_cache',
user => 'root',
minute => $minute, # this value will vary per host
}
}
Once you start using puppet to ensure your cronjobs are deployed across
your hosts you will often want to vary the time the cronjobs start, to
avoid placing excessive load on other resources. A good use case for
this functionality is when running a yum update
or similar expensive
command across all your machines. If you hard code the jobs timing, as
shown in the first resource below, every machine will contact the remote
host at the same time and drive its load up and the performance down.
Instead, dynamically set the minute using the fqdn_rand
function,
shown in the second resource, and the exact start time will be slightly
different across the hosts, reducing the pressure.
class good_vs_bad_cron {
# Hard coded. Every host runs at this exact time
cron { 'freshen_cache':
command => '/usr/local/sbin/freshen_cache',
user => 'root',
minute => 23,
}
# Much better - dynamic but consistent value
$minute = fqdn_rand(59)
# start time will vary across your hosts
cron { 'freshen_cache':
command => '/usr/local/sbin/freshen_cache',
user => 'root',
minute => $minute,
}
}
The fqdn_rand
function uses the fqdn
fact to create a random but repeatable
return value. Each node will get a different random number when calling
it, but the value will be the same on every run if the host name hasn't
changed. This allows puppet to set a value that is dynamic per host but
consistent between runs on that host. We can illustrate this by running
the same manifest a number of times on the same machine:
class minute_notify {
$minute = fqdn_rand(59)
notify { "I got ${minute} with fqdn ${fqdn}": }
}
include minute_notify
for ((i = 0 ; i < 5; i++))
do
puppet apply -v staggered_cron.pp 2>/dev/null | grep Staggered_cron
sleep 1
done
Notice: /Notify[I got 41 with fqdn puptest]/snip/
Notice: /Notify[I got 41 with fqdn puptest]/snip/
Notice: /Notify[I got 41 with fqdn puptest]/snip/
Notice: /Notify[I got 41 with fqdn puptest]/snip/
Notice: /Notify[I got 41 with fqdn puptest]/snip/
You can see in the output the number does not change between runs. To
verify the number does change between hosts we can override the fqdn
fact
and re-run our test using the same puppet code as before.
for ((i = 0 ; i < 5; i++))
do
# FACTER_fqdn overrides the facter value
FACTER_fqdn=puppet-cookbook puppet apply -v staggered_cron.pp \
2>/dev/null | grep Staggered_cron
sleep 1
done
Notice: /Notify[I got 33 with fqdn puppet-cookbook]/snip/
Notice: /Notify[I got 33 with fqdn puppet-cookbook]/snip/
Notice: /Notify[I got 33 with fqdn puppet-cookbook]/snip/
Notice: /Notify[I got 33 with fqdn puppet-cookbook]/snip/
Notice: /Notify[I got 33 with fqdn puppet-cookbook]/snip/
The fqdn
fact has changed so the number is different, but still
consistent between runs. This is the core of how all our crons continue
to run on a consistent, but varied, schedule. If you have cronjobs on a
single host that you need to stagger you can customise the fqdn_rand
call further and specify a specific name (technically a seed) to use
when generating the number. This allows you to vary the numbers on a
single host in a consistent way.
class single_host_stagger {
$batch = fqdn_rand(59, 'Data batch')
$repo = fqdn_rand(59, 'Freshen repos')
$backup = fqdn_rand(59, 'Backups')
notify { "Minutes: ${batch}, ${repo} and ${backup}": }
}
# Notice: Minutes: 41, 0 and 20