Cron 表达式是用于任务调度中表示时间计划的行业标准,几乎能够满足所有与时间有关的调度设置需求。如每天的凌晨1
点执行或每小时执行一次等,都可以用 Cron 表达式来表示。Keeper 对标准的 Cron 表达式进行了一些扩展,以满足更多应用场景的需要。
标准的的 Cron 表达式一共7
位,从左到右分别是:秒 分钟 小时 天 月 星期 年,每个时间位之间使用半角空格隔开。几个例子:
02:30
分执行 0 30 2 * * ? *
0 0 * * * ? *
0
分开始每隔5
分钟执行一次 0 0/5 * * * ? *
0 0 12 ? * MON-FRI *
9
点到下午18
点每小时的15
分执行一次执行 0 15 * W * ? *
0
点执行 0 0 0 ? * FR *
每个时间位的取值、支持的符号和关键词如下:
0
到59
,支持符号 *
,
-
/
。各个符号的意义见下面的介绍。0
到59
,支持符号 *
,
-
/
0
到23
,支持符号 *
,
-
/
1
到31
,支持符号 *
,
-
/
?
,支持关键字 F
、L
、W
、R
、FW
、FR
、LW
、LR
。有的关键词是 Keeper 进行的扩展,各个关键词的介绍见下面的说明。1
到12
,支持符号 *
,
-
/
,支持关键字 JAN
、FEB
、MAR
、APR
、MAY
、JUN
、JUL
、AUG
、SEP
、OCT
、NOV
、DEC
,分别代表1
到12
月。1
到7
,分别代表周一到周日,与标准的 Cron 表达式不同(1 表示周日,2 表示周一,依次类推),支持符号 *
,
-
+
#
?
,支持关键字 MON
、TUE
、WED
、THU
、FRI
、SAT
、SUN
,分别对应周一到周日。也支持关键字 F
、L
、W
、R
、FW
、FR
、LW
、LR
。1970
到2100
,支持符号 *
,
-
/
特别注意,在 Keeper 中,秒位始终为0
。有的应用场景中,Cron 表达式的位数不是7
位,如crontab
中会省略秒
和年
。Keeper 中支持1
到7
位的 Cron 表达式,见下面的说明。
在上面已经见到了好几个特殊符号,现将每个符号代表的意义说明如下:
全部
,代表每次都执行,如在分钟位表示0
到59
每分钟都执行,年位一般都设置成*
。区间
,如在小时位的5-10
表示5
点到10
点每小时都执行。列举
,如在星期位的MON,FRI,SAT
,表示在周一
、周五
和周六
执行。由逗号分隔的项中仍支持使用其他符号。间隔
,如在天位的1/2
,表示从1
号开始每隔2
天执行一次。在分钟位的0/10
表示从每小时的0
分开始,每隔10
分钟执行一次。注意 Keeper 不支持*/2
类似的设置,表示从当前时间开始每隔多少时间执行一次,但在其他应用如crontab
中支持。星期位不支持间隔设置,可使用列举全部列出来。互斥
,仅在天位和星期位支持,如果设置了天位,则星期位要设置成?
,如果设置了星期位,则天位要设置成?
。如果两个都设置了值,则优先天位的设置。第几周
,仅出现在星期位中,如MON#2
表示每月第2
周的周一
。和
,仅出现在星期位中且#
号前面。如MON-WED+FRI-SUN#2
表示每月第2
周的周一到周三加上周五到周日
。分隔
,在 Keeper 中,分号用来分隔多个 Cron 表达式,见下面的说明。属于
,在 Keeper 中,用于设置无限循环任务在不同时间段的时间间隔,见下面的说明。特别的,有些情况下设置等价,例如:
*
在秒位、分钟位、小时位等价于0/1
*
等价于1/1
等价于1,2,3,4,5,6,7
等价于MON,TUE,WED,THU,FRI,SAT,SUN
周
名称关键字和月
名称关键字只支持3
位的英文单词缩写,下面主要对其他的关键字进行介绍。
F
表示第一个,如每月第一天、每月第一周、每月第一个周一等L
表示最后一个,如每月最后一天、每月最后一周、每月倒数第几天,每月最后一个周五等W
表示工作日,一般为周一到周五,特殊工作日见下面的说明R
表示休息日,一般为周六和周日,特殊休息日如法定节假日的设置见后面的说明FW
表示第一个工作日,如每月或每周的第一个工作日FR
表示第一个休息日,如每月或每周的第一个休息日LW
表示最后一个工作日,如每月或每周的最后一个工作日LR
表示最后一个休息日,如每月或每周的最后一个休息日特别的,关键字不区分大小写。上面的F
和L
关键字还可以和其他的值组合,见天设置和星期设置。
在 Cron 表达式中的天设置相对复杂一些,有一些特殊的情况,比如每月的天数不固定、有工作日和节假日的区分等。分别举例说明如下:
1
号,用1
或F
表示FW
表示FR
表示LW
表示LR
表示L
表示L2
或2L
表示,倒数第3
天为L3
,依次类推10
号和11
号执行,用11,12
表示1
到10
号执行,用1-10
表示2
号开始双日执行,用2/2
表示;从1
号开始单日执行为1/2
1,9-15,16-24/2,25-L
,其中第三段表示16
号到24
号每隔2
天执行一次在 Cron 表达式设置中,星期的设置应该是最复杂的。分别举例说明如下:
MON
中1
表示,依次类推MON,FRI,SUN
或区间如MON-FRI
FW
表示FR
表示LW
表示LR
表示W
表示,由于法定节假日的原因,工作日和周一到周五的意义不同。R
表示,由于法定节假日的原因,休息日和周六周日的意义不同。#1
或#F
表示MON#F
表示第一周的周一、W#F
表示第一周的工作日#2
表示,依次类推。每月第三周的周一到周五,用1-5#3
表示1#4,3#4
或1+3#4
表示而不是1,3#4
(表示每周一和第四周的周三)1+2#2
表示第二周的周一和周二、1-3+5-6#3
表示第三周的除周四外的其他几天#L
表示,前面可以添加星期。 因为有的月份有6
周,有的月份有5
周,最少有4
周,所有用L表示最后一周。MON#F
、WED#6
、SUN#L
第一周和最后一周的设置有一些客观问题,即如果第一周或最后一周不存在指定的日期,如第一周不存在周一、最后一周不存在周日、甚至当月没有第六周。这种情况下本月不会有匹配结果,继续下一个月,直到找到匹配项。但是像SAT#6
,SUN#6
永远不会有匹配结果,一定注意。F1
或FMON
表示,注意不能用1#1
、MON#1
、1#F
、MON#F
表示,前者表示第一个周一,后者表示第一周的周一L5
或LFRI
表示,注意不能用5#L
或FRI#L
表示,两者的意义不同,一个表示最后一个周五,另一个表示最后一周的周五。FW#L
表示2WED
或23
表示,依次类推,最大值应该是5X
。FMON,F7,#2,1-5#3,FW#L,R#L
,每一段分别表示第一个周一,第一个周日,第二周的每天,第三周的周一到周五,最后一周的第一个工作日,最后一周的所有休息日用数字还是英文单词缩写表示星期依照个人习惯即可。
在日常使用中,月份一般为*
号。特殊情况下可以使用关键词或数字进行设置。
*
表示1/3
表示3/3
表示MAR-JUL
或3-7
表示3
月到7
月。4,6,8,10
或APR,JUN,AUG,OCT
表示4
月、6
月、8
月或10
月。每年都有一些法定节假日,也有一些公司的放假安排与法定节假日不同,比如春节法定节假日为7
天,有的公司可以放15
天。由于以上两种情况,所以在工作日W
和节假日R
设置时,不能完全按照周一到周五为工作日、周六和周日为休息日的来进行任务调度。
系统管理员或调度管理员可以在 Master 管理平台的“系统设置”->“Keeper 监控”->“工作日历”中进行设置。Keeper 会按照这个设置进行特殊工作日和特殊休息日的区分,如果没有设置,则仍然默认周一到周五为工作日、周六和周日为休息日。
上面提到 Keeper 支持1
到7
位的 Cron 表达式格式设置,是由于有的时间位字段值不会变,如秒位始终为0
,年位和月位一般都为*
等。下面分别说明一下不同位数格式都简化了什么:
1
位,仅表示分钟位,如30
等价于0 30 * * * ? *
,表示每小时的30
分执行2
位,仅表示分钟和小时位,如0 2
等价于0 0 2 * * ? *
,表示每天凌晨2
点整执行3
位,仅表示分钟、小时和天位,如0 9 W
等价于0 0 9 W * ? *
,表示每月的工作日的9
点整执行4
位,省略了秒、星期和年位5
位,省略了秒和年位,这两位一般情况下都不需要设置6
位,省略了秒位,在Keeper中秒位必须为0
除了标准的 Cron 表达式格式外,Keeper 还支持另外两种易读的表达式格式。
第一种格式和地址查询字符中类型,如HOUR=2&MINUTE=0
表示每天凌晨2
点执行,等价于0 2
。支持的参数名如下:
SECOND
秒MINUTE
分钟HOUR
小时DAY
天MONTH
月WEEK
周YEAR
年使用=
号对某一位进行设置,不同位设置之间使用&
号隔开。在这种格式中,仅需要设置需要的时间位,其他不需要设置的位可以省略。这种格式忽略设置的顺序,也可以规避错位的问题。
另一种格式更加易读,主要提供给非技术人员使用,如DAILY 12:00
表示每天中午12
点执行。常见的格式如下:
MINUTELY
表示每分钟执行,等价于0 * * * * ? *
HOUR 30
表示每小时30
分执行,等价于0 30 * * * ? *
HOUR 15,45
表示每小时15
分和45
分执行,等价于0 15,45 * * * ? *
DAILY 01:00
表示每天凌晨1点执行,等价于0 0 1 * * ? *
,每日任务在日常生产中最常见DAILY 9:30; 10:45
表示每天9:30
和10:45
(在标准 Cron 表达式中,不能通过一条表达式实现这个配置),等价于0 30 9 * * ? *; 0 45 10 * * ? *
DAILY 0-3,13:00
或DAILY 7,20:0/5
,可以理解为冒号左边是小时,右边是分钟,设置规则等同于标准的 Cron 表达式WEEKLY MONDAY 09:00
表示每周一早晨9
点执行,注意这里支持完整的星期名称MONTHLY WORKDAY 18:30
表示每个工作日的18:30
分钟执行,这里支持完整的关键字列表YEARLY JULY 1 12:00
表示每年的7
月1
日中午12
点执行,不过按年设置调度计划的情况非常之少这种格式支持非常多的关键词,这些关键词主要集中在WEEKLY
、MONTHLY
和YEARLY
三种模式中,简单列表如下:
MONDAY
,TUESDAY
,WEDNESDAY
,THURSDAY
,FRIDAY
,SATURDAY
,SUNDAY
MON
,TUE
,WED
,THU
,FRI
,SAT
,SUN
JANUARY
,FEBRUARY
,MARCH
,APRIL
,MAY
,JUNE
,JULY
,AUGUST
,SEPTEMBER
,OCTOBER
,NOVEMBER
,DECEMBER
JAN
,FEB
,MAR
,APR
,MAY
,JUN
,JUL
,AUG
,SEP
,OCT
,NOV
,DEC
WORKDAY
,HOLIDAY
FIRST-DAY
,LAST-DAY
,FIRST-WORKDAY
,LAST-HOLIDAY
,FIRST-HOLIDAY
,LAST-HOLIDAY
FIRST-WEEK
,SECOND-WEEK
,THIRD-WEEK
,FOURTH-WEEK
,FIFTH-WEEK
,SIX-WEEK
,LAST-WEEK
,表示这一周的任意一天-OF-FIRST-WEEK
,-OF-SECOND-WEEK
,-OF-THIRD-WEEK
,-OF-FOURTH-WEEK
,-OF-FIFTH-WEEK
,-OF-SIXTH-WEEK
,-OF-LAST-WEEK
。前面可以使用FIRST-WORKDAY
,FIRST-HOLIDAY
,WORKDAY
,HOLIDAY
或星期名,如WORKDAY-OF-FIRST-WEEK
, MONDAY-OF-FIRST-WEEK
FIRST-
,SECOND-
,THIRD-
,FOURTH-
,FIFTH-
,LAST-
。可以接星期关键词,如FIRST-MONDAY
,LAST-SUNDAY
等-TO-
,如MONDAY-TO-FRIDAY-OF-LAST-WEEK
,表示最后一周的周一到周五-AND-
,如MONDAY-AND-FRIDAY-OF-LAST-WEEK
,表示最后一周的周一和周五。可以和TO
混用,如MONDAY-TO-WEDNESDAY-AND-FRIDAY-OF-SECOND-WEEK
,表示第二周的周一到周三和周五同样的,以上关键字不区分大小写。
业务需求是复杂多变的,Cron 表达式虽然强大,但仍然不能完全涵养所有的需求。如业务要求任务在09:30
和10:45
各执行一次,这时一个表达式根本不能解决问题。Keeper 给出的解决方案是设置两个表达式,如30 9; 45 10
或DAILY 09:30; 10:45
。同样的,可以设置两个以上的表达式,多个表达式之间使用分号;
隔开即可,分号两端有没有空格都没关系。
Keeper 中支持无限循环任务,主要为数据准实时计算或数据大屏准备,比如每2
秒钟更新一次数据。但是这种实时更新是相对的,比如在工作时间早9
点到晚7
点有人看大屏的时候可以计算频繁一点,晚上非工作时间没人看的时候计算间隔设置长一些,以释放服务器的计算资源,供其他任务使用,特别是在晚上0
点到凌晨的计算高峰期。
Keeper 的解决方案是可以分段设置无限循环任务的时间间隔,如60; 2@* 9-18; 8@* 19-23
表示在9
点到18
点之间每隔2
秒执行一次,在19
点到23
点之间每隔8
秒执行一次,其他时间每隔60
秒执行一次。也可以不设置默认值,即在非指定的时间段不执行任务,如2@* 9-18; 8@* 19-23
,即在0
点到8
点之间不执行任务。
在 PQL 的依赖包中,提供了几个类用于 Cron 表达式的解析,包路径为io.qross.time
。
以上几个类属于 DataHub 框架的一部分。在 PQL 中,同样提供了对应的 Sharp 表达式用于 Cron 表达式操作,详细点击这里。
参考链接