今天配置了一下Jenkins作为简单的定时作业配置,辅助线上的一些手动处理作业。配置到Build Perodemically的时候,觉得这种cron配置好像很多地方都见过。所以这里总结一下,方便系统地认识理解和使用这个工具与规则。
【cron与crontab】
在Unix与类Unix系统(Linux,MacOS...)中,cron不是具体的某个工具,而是运行定时计划操作的服务的统称,相当于Windows下的scheduled task。
在Linux中crond服务位于/etc/rc.d/init.d/crond 或 /etc/init.d 或 /etc/rc.d /rc5.d/S90crond,最终引用/var/lock/subsys/crond。crond 是在后台运行并读取 crontab 文件的守护进程的名称。在Linux中,crond作为一个后台服务(deamon),一般随系统的启动而启动,我们可以通过启动、关闭以及重启、重载crond服务来控制是否可以使用定时任务功能。
/sbin/service crond start //启动服务 /sbin/service crond stop //关闭服务 /sbin/service crond restart //重启服务 /sbin/service crond reload //重新载入配置
你也可以将这个服务在系统启动的时候自动启动:
在/etc/rc.d/rc.local这个脚本的末尾加上:
/sbin/service crond start
cron 是运行计划操作的服务;而crontab 是包含固定格式的作业文件,用以支撑这个cron服务。在不同的发行版中,Linux中的cron服务使用文件夹/etc/rc.d/或/etc/init.d,每分钟检查文件/etc/crontab 或/var/spool/Cron,查找我们计划的可能执行。而在crontab这个文本文件中,具有特殊格式的内容,专门设计用于 cron 正确读取并继续执行我们编写的程序。有一个包含所有要执行的脚本的列表,通常系统的每个用户都有他们自己的 crontab 文件,这样,每个用户都可以独立安排他们自己的重复任务,而不需要我们总是去管理员用户那里。通过这种方式,任何用户(包括管理员)都可以安排重复任务来执行不同的执行。
【cron与crontab的格式】
两者的格式并不相同。这里没有查到来源是什么,但我的理解就是cron是系统内部真正执行指令的最终格式,而crontab的格式是类Unix系统提供给用户使用的格式。
规则上,crontab的语法相对要简单一些,字符串中的5位,从左到右分别是“分时日月星”,如图:
而cron的语法则是6位或者7位(包含一个可选的年)。即“秒分时日月星”或者“秒分时日月星年”。cron的规则中包含了crontab的规则,这里就以cron的规则进行说明(参考了https://www.bejson.com/othertools/cronvalidate/):
注意事项:
每一个域都使用数字,但还可以出现如下特殊字符,它们的含义是:
(1)*:表示匹配该域的任意值。假如在Minutes域使用*, 即表示每分钟都会触发事件。
(2)?:只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。因为DayofMonth和DayofWeek会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用*,如果使用*表示不管星期几都会触发,实际上并不是这样。
(3)-:表示范围。例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次
(4)/:表示起始时间开始触发,然后每隔固定时间触发一次。例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次.
(5),:表示列出枚举值。例如:在Minutes域使用5,20,则意味着在5和20分每分钟触发一次。
(6)L:表示最后,只能出现在DayofWeek和DayofMonth域。如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。
(7)W:表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件。例如:在 DayofMonth使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日(周一)触发;如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份 。
(8)LW:这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。
(9)#:用于确定每个月第几个星期几,只能出现在DayofWeek域。例如在4#2,表示某月的第二个星期三。
有两个比较实用的网站可以检查你的cron和crontab规则是否正确:
https://www.bejson.com/othertools/cronvalidate/
https://www.geekstool.com/crontab.html
很多语言框架或者工具中都是带了这两种规则类型的定时服务的一种,查看官网文档,然后确认好是哪一种规则,一般来说,具体的规则和上述的应该一致。
【jenkins中的crontab】
在Jenkins的定时任务中,也遵循分时日月星的原则,但会有一些不同(minor differences)。以下是原文对于规则的描述:
其中主要的区别就是这个H的使用,H代表hash,说明中提到要在一切可能的地方使用这个H符号,使系统上的负载更为均衡。这里其实不用H,直接采用crontab那一套规则也是可以运行的,但是毕竟是官方推荐的做法,还是应该遵循。
【java中的cron】
在spring中常用@Schedule(cron="")的注解来进行定时任务的设置。这里的cron遵循的是cron规则,即 秒分时日月星或者秒分时日月星年的写法。
在java中,有一些第三方包可以很方便地验证这个cron字符串是否符合规则,如:
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.3.0</version> </dependency>
具体的用法如下:
package test; import org.quartz.CronExpression; public class QuartzTest { public static void main(String[] args) { // 验证cron定时表达式的正确性 String cron = "0/50 * * * * ?"; // 调用提供的API boolean validExpression = CronExpression.isValidExpression(cron); System.out.println(validExpression); // 表达式正确输出true、不正确则输出flase } }
【cron常见的例子】
了解了上面的来源、定义、区别、规则,这里提供一些常用的规则配置。如果是想快速的配置一些场景的cron或者crontab字符串,可以类比此处的字符串:
---cron规则:秒分时日月星、秒分时日月星年
0 0 2 1 * ? * 表示在每月的1日的凌晨2点调整任务
0 15 10 ? * MON-FRI 表示周一到周五每天上午10:15执行作业
0 15 10 ? 6L 2002-2006 表示2002-2006年的每个月的最后一个星期五上午10:15执行作
0 0 10,14,16 * * ? 每天上午10点,下午2点,4点
0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时
0 0 12 ? * WED 表示每个星期三中午12点
0 0 12 * * ? 每天中午12点触发
0 15 10 ? * * 每天上午10:15触发
0 15 10 * * ? 每天上午10:15触发
0 15 10 * * ? * 每天上午10:15触发
0 15 10 * * ? 2005 2005年的每天上午10:15触发
0 * 14 * * ? 在每天下午2点到下午2:59期间的每1分钟触发
0 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟触发
0 0/5 14,18 * * ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
0 0-5 14 * * ? 在每天下午2点到下午2:05期间的每1分钟触发
0 10,44 14 ? 3 WED 每年三月的星期三的下午2:10和2:44触发
0 15 10 ? * MON-FRI 周一至周五的上午10:15触发
0 15 10 15 * ? 每月15日上午10:15触发
0 15 10 L * ? 每月最后一日的上午10:15触发
0 15 10 ? * 6L 每月的最后一个星期五上午10:15触发
0 15 10 ? * 6L 2002-2005 2002年至2005年的每月的最后一个星期五上午10:15触发
0 15 10 ? * 6#3 每月的第三个星期五上午10:15触发
----crontab规则:分时日月星
每分钟执行 --------- * * * * *
每2分钟执行 --------- */2 * * * *
每小时的2分执行 --------- 2 * * * *
每半小时执行 --------- */30 * * * *
分钟是50分的倍数时执行 --------- */50 * * * *
每天整点执行 --------- 0 * * * *
每小时的15分执行 --------- 15 * * * *
每天 12点5分 执行 --------- 5 12 * * *
每天 10点到18点 整点执行 --------- 0 10-18 * * *
每天 10点和18点 半点执行 --------- 30 10,18 * * *
从0点开始,每隔4小时 半点执行 --------- 30 */4 * * *
从1点开始,每隔4小时 半点执行 --------- 30 1-23/4 * * *
每周六中午12点执行 --------- 0 12 * * 6
每周二、四、六中午12点执行 --------- 0 12 * * 2-6/2
周末中午12点执行 --------- 0 12 * * sat,sun
每周日的凌晨0点执行 --------- 0 0 * * 0
每周一、二 的 8点和12点执行 --------- 0 8,12 * * 1,2
每月1日的凌晨0点执行 --------- 0 0 1 * *
每月25日的17点执行 --------- 0 17 25 * *
每单数月份的25日的17点执行 --------- 0 17 25 */2 *