I would just like to sum up my recent encounter with cronie and its' default config on gentoo, and raise a few questions.
Thanks to people on irc and irl who helped me with this.
I was interested in system-wide cron jobs (not user crontabs).
vixie-cron is now removed from portage, so let's begin with installing cronie:
Code: Select all
gentoo /etc # emerge -av sys-process/cronie
These are the packages that would be merged, in order:
Calculating dependencies... done!
[ebuild N ] sys-process/cronbase-0.3.7-r6::gentoo 0 KiB
[ebuild N ] sys-process/cronie-1.5.5::gentoo USE="anacron inotify pam (-selinux)" 0 KiB
Total: 2 packages (2 new), Size of downloads: 0 KiB
...
note: by default, "anacron" USE flag is enabled, so /usr/sbin/anacron will get installed.
Code: Select all
gentoo ~ # qlist -e cronie | grep bin
/usr/bin/crontab
/usr/bin/cronnext
/usr/sbin/crond
/usr/sbin/anacron
gentoo /etc # qlist -e cronbase | grep bin
/usr/sbin/run-crons
Code: Select all
gentoo ~ # /etc/init.d/cronie start
My main question was: How exactly does the /etc/cron.{hourly,daily,weekly,monthly} work?
Let's find out.
The starting point for me was /etc/crontab (I knew about this file before)
Code: Select all
gentoo ~ # cat /etc/crontab
# Global variables
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/
# For details see man 5 crontab
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
Code: Select all
gentoo ~ # man 5 crontab
...
Jobs in /etc/cron.d/
The jobs in cron.d and /etc/crontab are system jobs, which are used
usually for more than one user, thus, additionally the username is
needed. MAILTO on the first line is optional.
...
Code: Select all
gentoo ~ # ls /etc/cron.d
0hourly
gentoo ~ # cat /etc/cron.d/0hourly
# Run the hourly jobs
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
01 * * * * root run-parts /etc/cron.hourly
That would explain how jobs in /etc/cron.hourly would get run (hourly).
Fine, but what about /etc/cron.{daily,weekly,monthly}? Let's investigate further.
Where does run-parts come from and what does it do:
Code: Select all
gentoo ~ # which run-parts
/bin/run-parts
gentoo ~ # qfile /bin/run-parts
sys-apps/debianutils: /bin/run-parts
gentoo ~ # man run-parts
...
run-parts runs all the executable files named within constraints described
below, found in directory directory . Other files and directories are silently ignored.
...
Files are run in the lexical sort order
...
Code: Select all
gentoo ~ # ls -l /etc/cron.hourly/
total 4
-rwxr-x--- 1 root root 580 Feb 8 11:29 0anacron
Code: Select all
gentoo ~ # cat /etc/cron.hourly/0anacron
#!/bin/sh
# Check whether 0anacron was run today already
if test -r /var/spool/anacron/cron.daily; then
day=`cat /var/spool/anacron/cron.daily`
fi
if [ `date +%Y%m%d` = "$day" ]; then
exit 0
fi
# Do not run jobs when on battery power
online=1
for psupply in AC ADP{0..9} ; do
sysfile="/sys/class/power_supply/$psupply/online"
if [ -f $sysfile ] ; then
if [ `cat $sysfile 2>/dev/null`x = 1x ]; then
online=1
break
else
online=0
fi
fi
done
if [ $online = 0 ]; then
exit 0
fi
/usr/sbin/anacron -s
So cron is (by default) running anacron. Seems weird? It did to me, but I later found on gentoo wiki
"Anacron is not a cron daemon, it is something that usually works in conjunction with one.".
Only thing contraintuitive is that there is also a solo package sys-process/anacron in portage (that's different anacron implementation).
Anyway, back to the anacron which came with cronie
Code: Select all
gentoo ~ # man anacron
...
Anacron is used to execute commands periodically, with a frequency
specified in days.
...
Anacron reads a list of jobs from the /etc/anacrontab configuration
file (see anacrontab(5))
...
Code: Select all
gentoo ~ # cat /etc/anacrontab
# /etc/anacrontab: configuration file for anacron
# See anacron(8) and anacrontab(5) for details.
SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
# the maximal random delay added to the base delay of the jobs
RANDOM_DELAY=45
# the jobs will be started during the following hours only
START_HOURS_RANGE=3-22
#period in days delay in minutes job-identifier command
1 5 cron.daily nice run-parts /etc/cron.daily
7 25 cron.weekly nice run-parts /etc/cron.weekly
@monthly 45 cron.monthly nice run-parts /etc/cron.monthly
The whole line is like follows:
"/etc/init.d/cronie start" -> crond started, reads "/etc/cron.d/0hourly"
-> "run-parts /etc/cron.hourly" -> runs "/etc/cron.hourly/0anacron" on every <hour>:01
-> runs "/usr/sbin/anacron -s" once a day -> interprets /etc/anacrontab -> runs /etc/cron.{daily,weekly,monthly}
So /etc/cron.{hourly,daily,weekly,monthly} is a mixed bag, wrt how they are executed: /etc/cron.hourly is run directly by crond, whereas /etc/cron.{daily,weekly,monthly} is run indirectly by anacron, which is run by crond
note: anacron cannot start hourly jobs
Question: starting times So when exactly do the cron jobs start?
For jobs in /etc/cron.hourly, the answer is - they will start once 0anacron is done (since 0anacron is usually alphabetically first).
0anacron has a check for running once a day only, "anacron -s" becomes a sleeping process, so mostly the hourly jobs will be run at <hour>:01
When does anacron run the jobs i.e. when do the /etc/cron.{daily,weekly,monthly} start is (afaict) random - there is delay+random delay,
there is START_HOURS_RANGE. Tbh, I had not investigated this that much.
Question: reentrancy (overlapping hourly jobs)
The most important question for me was: will crond start a new (hourly)
job even if the previous instance is still running?
The answer for /etc/cron.hourly/ is a definite yes, happily (tested it experimentally with job containing sleep 65m)
reason: in my case, there is a shell script in /etc/cron.hourly, that synchronizes files from other server, using rsync, and I would not like two rsynces running at the same time (if the sync takes more than an hour).
note: I was advised, that it is a good thing to use flock inside the sync script, something like (a fully atomic way of preventing the race condition)
Code: Select all
...
exec 9>/var/run/myscript.lock; flock -n 9 || exit
...
Perhaps anacron in itself prevents the concurrent running? Really not sure
Code: Select all
gentoo ~ # man anacron
...
-s Serializes execution of jobs. Anacron does not start a new job
before the previous one finished.
...
So perhaps more than one instance of "anacron -s" could finally be running (if the job takes more than 24h). Again, here I am unsure.
Final note
Previously, with vixie-cron (now removed from the tree), the running of /etc/cron.{hourly,daily,weekly,monthly} was accomplished in a different way - /etc/crontab contained (by default) the following:
Code: Select all
59 * * * * root rm -f /var/spool/cron/lastrun/cron.hourly
9 3 * * * root rm -f /var/spool/cron/lastrun/cron.daily
19 4 * * 6 root rm -f /var/spool/cron/lastrun/cron.weekly
29 5 1 * * root rm -f /var/spool/cron/lastrun/cron.monthly
*/10 * * * * root test -x /usr/sbin/run-crons && /usr/sbin/run-crons
Code: Select all
#01 * * * * root run-parts /etc/cron.hourlyCode: Select all
gentoo ~ # chmod -x /etc/cron.hourly/0anacronEDIT: beware - upon reinstalling or updating sys-process/cronie, the executable bit on /etc/cron.hourly/0anacron gets silently enabled again, switching on anacron. So rather than "chmod -x", it is probably better to edit 0anacron and comment out the line with "anacron -s".
The advantage of using the above config, i.e. relying on run-crons script over anacron is probably better control on when exactly the daily,weekly,monthly scripts will get run (though you can setup random delay to zero and have that control with anacron too). Every ten minutes /usr/sbin/run-crons would be run (if it was executable). It would check the /var/spool/cron/lastrun/cron.* files, and run executables in /etc/cron.hourly/* on every <hour>:00, /etc/cron.daily/* on 3:10am, /etc/cron.weekly/* on every saturday 4:20am, /etc/cron.monthly/* on 5:30am every first day of the month.
I have verified experimentally, that the run-crons script (still provided nowadays with sys-process/cronbase) prevents the reentrant execution of the /etc/cron.hourly/ scripts.
To that end, I have created a script
Code: Select all
gentoo ~ # cat /etc/cron.hourly/test65m
#!/bin/sh
ST=`date +%s`
touch /root/crontest/${ST}start
sleep 65m
touch /root/crontest/${ST}end
Code: Select all
gentoo ~ # ls -l /root/crontest/
-rw-r--r-- 1 root root 0 Feb 8 02:00 1581123601start
-rw-r--r-- 1 root root 0 Feb 8 03:05 1581123601end
-rw-r--r-- 1 root root 0 Feb 8 03:10 1581127801start
-rw-r--r-- 1 root root 0 Feb 8 04:15 1581127801end
-rw-r--r-- 1 root root 0 Feb 8 04:20 1581132002start
-rw-r--r-- 1 root root 0 Feb 8 05:25 1581132002end
-rw-r--r-- 1 root root 0 Feb 8 05:30 1581136201start
-rw-r--r-- 1 root root 0 Feb 8 06:35 1581136201end
-rw-r--r-- 1 root root 0 Feb 8 06:40 1581140401start
-rw-r--r-- 1 root root 0 Feb 8 07:45 1581140401end
-rw-r--r-- 1 root root 0 Feb 8 07:50 1581144601start
-rw-r--r-- 1 root root 0 Feb 8 08:55 1581144601end
https://gitweb.gentoo.org/repo/gentoo.g ... 5e19d749f8
https://gitweb.gentoo.org/repo/gentoo.g ... 5785cbb7c1
https://gitweb.gentoo.org/repo/gentoo.g ... 9d5f497a59
