需求
当我们想要在Linux系统上执行一个定时任务时,我们会一般使用到crontab。但是由于crontab本身是分钟级的定时任务执行机制,会导致我们无法直接配置一个秒级的定时任务
解决方案
多次延时执行
有一种实现方式是,配置一个定时任务每分钟执行多次(就是多写几个触发),依靠每次定时任务执行前预先执行sleep语句,达到错开时间执行的效果
例如:有一个定时任务脚本task.sh,预期10s执行一次,那么可以算得在一分钟内执行6次,每次间隔10s
则配置6个定时任务,第一个定时任务直接执行无延时,第二个延时10s,第三个延时20s,直到第六个延时50s。以此来达到10s执行一次的效果
但是这个方案的缺点也很明显,10s执行一次及已经需要配置6个定时任务了,执行时间间隔越短就意味着需要配置的定时任务越多,而且如果执行间隔不能被60整除,也将可能导致需要配置更多定时任务来实现
分钟级脚本自主实现秒级执行
由于crontab本身是分钟级的定时任务执行机制
针对秒级执行定时任务的需求
我们可以写出一个循环语句,间隔一段时间执行某段指令,以达到秒级定时任务的效果
还是前面提到的例子:有一个定时任务脚本task.sh,预期10s执行一次
那么可以写个简单的循环,设置一个变量初始值为0,执行一些指令并使该变量自增10,然后调用sleep语句睡眠10s,直到该变量值达到或超过60为止
这样可以保证task.sh每10s执行一次
但是如此设计便引出另一个问题
如果脚本执行的间隔时间并不能被60s整除,那么这个简单的方式便无法满足需求了
例如:有一个定时任务脚本task.sh,预期7s执行一次
按照之前的方案,那么执行节点会是:0s,7s,14s......49s,56s,0s
问题出在56s执行之后,间隔了4s就又执行了一次
原因也非常简单,第二分钟的定时任务依旧是从0s开始计算,上一分钟的定时任务执行结果,第二分钟是不知道的
那么如何解决这个问题呢
按照预期的间隔7s,第二分钟的定时任务应当在3s执行,又或者说,63s,然后接下来是70s,77s......
那么我们设计的定时任务,总共执行时间就需要超过一分钟,但是又要保证总共花费的时间是能被n分钟整除的,因为crontab的分钟级定时任务执行机制
所以我们优化一下之前的脚本,新增一个执行分钟数,那么我们可以设置定时task.sh脚本每7分钟触发一次,每次执行7分钟,这样7s间隔就可以被7分钟整除
脚本如下
#!/bin/bash
executeInterval=7
executeMinutes=7
# max time(s)
nowSeconds=0
maxSeconds=$((executeMinutes * 60))
times=0
while (($nowSeconds < $maxSeconds))
do
times=$((++times))
nowSeconds=$((nowSeconds + executeInterval))
# echo "`date +'%Y-%m-%d %H:%M:%S'`: No.$times executing at $nowSeconds second."
# To do something start
# To do something end
sleep $executeInterval
done
显而易见,有一个数值7被赋值给两个变量了,我们只需要一个变量就可以完成这件事,那么我们直接将两个变量合成一个变量
这时候我们会忽然发现,现在定时任务cron表达式将为“*/7 * * * *”,现在cron表达式中的7,好像意味着,每隔7s执行一次了!