相关文章推荐

Keeper 中的 Cron 表达式

Cron 表达式是用于任务调度中表示时间计划的行业标准,几乎能够满足所有与时间有关的调度设置需求。如每天的凌晨 1 点执行或每小时执行一次等,都可以用 Cron 表达式来表示。Keeper 对标准的 Cron 表达式进行了一些扩展,以满足更多应用场景的需要。

标准的的 Cron 表达式一共 7 位,从左到右分别是: 秒 分钟 小时 天 月 星期 年 ,每个时间位之间使用半角空格隔开。几个例子:

  • 每天凌晨 02:30 分执行 0 30 2 * * ? *
  • 每小时整点执行 0 0 * * * ? *
  • 0 分开始每隔 5 分钟执行一次 0 0/5 * * * ? *
  • 周一到周五每天中午12点执行 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

  • ChronExp 类,传递任意格式的表达式, 详情点击
  • CronExp 类,用于标准格式的 Cron 表达式解析, 详情点击
  • DateTime 类,基础的日期时间类, 详情点击
  • 以上几个类属于 DataHub 框架 的一部分。在 PQL 中,同样提供了对应的 Sharp 表达式 用于 Cron 表达式操作,详细 点击这里

  • Keeper 中的调度作业
  • DataHub 开发框架
  •  
    推荐文章