Linux实现秒级定时任务

发布时间 2023-12-06 14:20:30作者: PlaidShirtWholesaler

需求

当我们想要在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执行一次了!