# 可唤醒停机期间的工作任务

考虑一个场景:你有一个定时任务,每周星期天凌晨 2 点 ,执行一次,但是很不幸,这个时间点停电了,等你上班周 1 去开机时,这个定时任务句错过了执行时机。

这种情况下,需要靠 anacron 指令:主动帮你进行时间到了但却没有执行的定时任务

# 什么是 anacron

anacron:主动帮你进行时间到了但却没有执行的定时任务,不是来替代 crond 的

anacron 其实是前面谈到过的,每小时被 crond 执行一次,会去检测相关定时任务是否有执行,由于 anacron 预设以 每天、每周、每个月去检查未进行的 crontab 任务,因此对于某些特殊的使用环境非常有帮助

比如:你的主机,是共用的,周末 2 天没有人使用,需要关机,但是有一些任务在周日早上执行,而又关机了,那么重新开机的时候,就可以利用 anacron 的功能,执行没有执行的任务。

anacron 读取的时间记录文件(timestamps),分析现在的时间记录文件所记载的上次执行 anacron 的时间,两者比较后若发现有差异,那就是在某些时刻没有进行 crontab,此时就会开始执行未进行的 crontab 任务

简要说:anacron 的原理是,依赖每小时的执行一次的任务记录下时间,下一次执行时,对比当前时间的差异,如果中间有缺少执行,那么表示 crontab 任务在这期间没有被执行过(笔者有疑问就是,一小时,那么怎么知道每小时的 5 分钟到 59 分这个时间点的任务是否被执行过了呢?)

# anacron 与 /etc/anacrontab

anacron 不是一个服务,是一个程序,每小时被主动执行一次,所以 anacron 的配置文件放置在 /etc/cron.hourly/ 目录中的

[root@study ~]# cat /etc/cron.hourly/   
0anacron     mcelog.cron  
[root@study ~]# 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
# 上面校验前一次执行 anacron 时间的时间戳 

# Do not run jobs when on battery power
if test -x /usr/bin/on_ac_power; then
    /usr/bin/on_ac_power >/dev/null 2>&1
    if test $? -eq 1; then
    exit 0
    fi
fi
/usr/sbin/anacron -s
# 经过了一些判断,然后执行了 anacron  -s 指令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
anacron [-sfn] [job]..
anacron -u [job]...

选项与参数:
	-s:开始一连续的执行各项工作 job,会依据时间记录文件的数据判断是否进行
	-f:强制进行,而不去判断时间记录文件的时间戳
	-n:like进行未进行的任务,而不言辞(delay)等待时间
	-u:仅更新时间记录文件的时间戳,不进行任何工作
	job:由 /etc/anacrontab 定义的各项工作名称
1
2
3
4
5
6
7
8
9

在 CentOS 中,anacron 每小时都会执行一次,为了担心 anacron 误判时间参数,因此 /etc/cron.hourly/ 中的 anacron 文件名前加了一个 0(0anacron),让 anacron 最先执行。

[root@study ~]# 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@study ~]# more /var/spool/anacron/*
::::::::::::::
/var/spool/anacron/cron.daily
::::::::::::::
20200308
::::::::::::::
/var/spool/anacron/cron.monthly
::::::::::::::
20200212
::::::::::::::
/var/spool/anacron/cron.weekly
::::::::::::::
20200308

# 上面则是三个工作名称的时间记录文件以及记录的时间戳
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

/etc/cron.daily 的设置来说明:

  • 天数:anacron 执行当前与时间戳(/var/spool/anacron 内时间记录文件)相差的天数,若超过此天数,就准备开始执行,若没有超过此天数,则不执行后续的指令
  • 延迟时间:若确定超过天数导致要执行任务了,那么延迟执行的时间,因为担心立即启动会有其他资源冲突的问题
  • 工作名称定义:无意义,只在 /var/log/cron 里记录的名称,通常与后续的目录资源名相同
  • 实际要进行的指令串:与 0hourly 很细,通过 run-parts 来处理的

根据上面的配置文件内容,大概知道 anacron 的执行流程应该如下(以 cron.daily 为例):

  1. /etc/anacrontab 分析到 cron.daily 这项工作名称的天数为 1 天
  2. /var/spool/anacron/cron.daily 取出最仅一次执行 anacron 的时间戳
  3. 又上个步骤与目前的时间比较,若相差 1 天以上(含 1 天),就准备进行指令
  4. 若准备进行指令,根据 /etc/anacrontab 的设置,将延迟 5 分钟 + 3 小时(看 START_HOURS_RANGE 的设置)
  5. 延迟时间后,开始执行后续指令,即 run-parts /etc/cron.daily 指令
  6. 执行完毕后,anacron 程序结束

这也是为什么你的系统开机后,一小时左右会有一段时间忙碌,就是因为在执行上述的配置任务

# 总结:crond 与 anacron 的关系

  1. crond 会主动读取 /etc/crontab、/var/spool/cron/*、/etc/cron.d/* 等配置文件,并依据设置的时间去执行任务
  2. 根据 /etc/cron.d/0hourly 的配置,主动去 /etc/cron.hourly/ 目录下,执行所有在该目录下的执行文件
  3. 因为 /etc/cron.houly/0anacron 脚本文件的缘故,主动的每小时执行 anacron,并调用 /etc/anacrontab 的配置文件
  4. 根据 /etc/anacrontab 的配置,每天、每周、每月去分析 /etc/cron.daily、/etc/cron.weekly、/etc/cron.monthly 内的执行文件,进行固定周期所执行的指令

也就是说,如果你每个周日所需要执行的配置是放置在 /etc/crontab 中的话,那么该动作只要过期了就过期了,而放在 /etc/cron.weekly 目录下,那么该工作就会定期,每周执行一次的频率,如果你关机超过一周,那么开机后的数个小时内,该工作就会主动的被执行