Cron 模块构思

需求点

  • 单个时间点的定时任务: 每周的某几天的某个时刻执行某个任务
  • 多个时间点的定时任务:每周的某几天的某几个时刻执行某个任务
  • 单个时间段的频率任务:每周的某几天的某个时间段,以固定的频率重复执行某个任务
  • 多个时间段的频率任务:每周的某几天的某几个时间段,以固定的频率重复执行某个任务

选型

  1. 依赖于Cron模块,如本机cron功能,或者框架的cron功能
    • 优点: 使用较为简单
    • 缺点:需要解决集群情况下,多服务器重复调用执行的问题。如果是系统的crontab功能,很难针对某一条cronjob做处理,如果是框架的cron则无此问题。
  2. 依赖于cloudwatch的schedule功能
    • 优点:不用担心集群重复调用问题。
    • 缺点:代码量增多、额外的云端运维成本、需要额外的lambda函数支持、如果用户回调不是纯函数,会丢失对应上下文环境

模块定义

总览

  • 模块入口
interface CronModule {
    create(options:CreateOptionsType):Promise<Result>;
    createBySchedule(options:CreateOptions<CronType.SCHEDULE>):Promise<Result>;
      createByFrequency(options:CreateOptions<CronType.FREQUENCY>):Promise<Result>;
    createByCronExpression(options:CreateOptions<CronType.CronExpression>):Promise<Result>;
    list():Promise<Array<CronInfo>>;
    start(id:string):Promise<Result>;
    startAll():Promise<Result>;
    stop(id:string):Promise<Result>;
      stopAll():Promise<Result>;
    edit(id:string, editData:EditOptions<CronType>);
    describe(id:string):Promise<CronInfo>;
    delete(id:string):Promise<Result>;
}
  • 类型定义
enum CronType{
        SCHEDULE, // 一周内某几天中的某几个时间点执行
        FREQUENCY, // 一周内某几天中的某几个时间段,按照一定频率重复执行
        CronExpression
}

enum CronStatus{
    ACTIVE, // 生效中
    INACTIVE //未生效,禁用中
}

type CronString = string; // cron 表达式
type CreateOptionsType = CreateOptions<CronType.SCHEDULE> |
                            CreateOptions<CronType.FREQUENCY> |
                            CreateOptions<CronType.CronExpression>;

interface Result{
    success:boolean;
    err?:Error;
      data:any;
}

interface CronInfo{
    status:CronStatus;
    options:CreateOptionsType
}

interface TimeCell{
    second: number;
    minute: number;
    hour: number;
}
  • Schedule调用类型
interface CreateOptions<CronType.SCHEDULE>{
        name?: string;
        type:CronType.SCHEDULE;
        scheduleRules:Array<ScheduleRule>;
        callback:any=>void;
        callbackParams:any;
}

interface ScheduleRule{
        scheduleTime: TimeCell | string;
        weekdays?:number; // 7位2进制的10进制表示
}
  • Frequency调用类型
interface CreateOptions<CronType.FREQUENCY>{
        name?: string;
        type:CronType.FREQUENCY;
        frequencyRules:Array<FrequencyRule>;
        callback:any=>void;
        callbackParams:any;    
}

interface FrequencyRule{
        startTime?:TimeCell | string; // default 00:00
        endTime?:TimeCell; // default 23:59
        frequency?:number; // 以秒为单位 default 60, means every 60 seconds
        weekdays?:number; // 7位2进制的10进制表示
}
  • CronExpression调用类型
interface CreateOptions<CronType.CronExpression>{
        name?: string;
        type:CronType.CronExpression;
        cronExpressions:Array<string>;
        callback:any=>void;
        callbackParams:any;    
}

接口描述

create

        create(options:CreateOptionsType)=>Promise<Result>;

根据传入参数不同,创建一个对应的cron任务写入到数据库,默认状态为DISABLED, 等宿主调用startAll()或者start()函数时,会变为ENABLE状态并生成对应的cronjob正式启动。

例如:

// 周一到周六,每天12:00以及13:05都会执行一次callback,附带参数{}
create({
    name:"test1",
    type:CronType.SCHEDULE,
    scheduleRules:[{hour:12, weekdays:127}, {hour:13, minute:5, weekdays:127}],
    callback:(data)=>console.log("fired"),
    callbackParams:{},
})

// 每天每小时执行一次callback,附带参数{}
create({
    name:"test2",
    type:CronType.FREQUENCY,
    frequencyRules:[{frequency:60*60}],
    callback:data=>console.log("fired"),
    callbackParams:{},
})

startAll

startAll():Promise<Result>;

启动数据库中所有存储的cron,生成对应的cronjob。一般在服务器启动时调用

start

start(id:string):Promise<Result>;

单独启动某一cron

list

list():Promise<Array<CronInfo>>;

列出当前数据库中所有的cron信息

describe

describe(id:string):Promise<CronInfo>;

单独列出某一个cron相关信息

delete

delete(id:string):Promise<Result>;

删除某一特定cron,如果该cron已生成了对应的cronjob并正在运行,也会删除对应cronjob

stop

stop(id:string):Promise<Result>;

将数据库中某一cron状态设置为DISABLED状态,但不删除,并如果该cron生成了对应的cronjob,会删除对应的cronjob

数据库设计

id: number cronId: string cronType: CronType status: CronStatus scheduleRule: {} frequencyRule: {} cronExpression: string callback: string callbackParams: {} createdAt: date updatedAt: date

补充

  • cron任务集群解决方案收集:
    • 通过env设置的方式,使cron服务只在一台服务器上生效
      • 优点:处理方便
      • 缺点:不优雅、如果该主机宕机,cron服务则直接崩溃
    • 通过外置的redis设置交互锁
      • 优点:保证了cron的集群部署,保证各集群主机环境统一
      • 缺点:额外的redis依赖,额外的交互锁逻辑代码
  • 思考:
    • 在Service模式的情况下,如何才能让宿主注册回调函数并且不丢失运行上下文?

results matching ""

    No results matching ""