Code Monkey home page Code Monkey logo

wilsonliu95 / tfschedule Goto Github PK

View Code? Open in Web Editor NEW
32.0 4.0 9.0 3.56 MB

node版定时任务管理模块,告别 crontab 管理诸多批跑任务的繁琐,可视化管理任务与历史执行记录。 特性:高稳定,放心使用;弱侵入,方便迁移;web可视化管理任务,任务与执行记录相关信息入DB;可查各次任务执行日志与发布的文件;11类异常告警,避免后知后觉;多语言支持,自定义执行器与任务入口文件。

License: MIT License

JavaScript 66.60% HTML 33.40%
node node-schedule sche-task-monitor

tfschedule's Introduction

欢迎个人与团队的接入使用 or 提供建议 or 反馈BUG,使用过程中有任何疑问,欢迎私戳~ QQ群号:615501183

注:原名 schedule_task_monitor, 经过代码重构与优化并改名为TFSchedule。 新增特性支持多语言,即指定执行器与入口文件,并细分告警类型,强化异常处理逻辑,推荐迁移到TFSchedule

TODO: 目前为单机部署版本,3.0版本将加入分布式任务调度特性,以下为3.0的设想欢迎讨论~。

  1. 在实际调度机器上部署client
    • client用于从统一DB内读取属于自己的任务列表挂载执行
    • 同步日志到server
    • 同步产生的文件server
  2. 一台机器用作web服务器
    • 接收client同步来的日志及文件
    • 部署web服务器 提供可视化操作
    • 修改DB

背景

随着node的出现与发展,前端承担了越来越多的职责。

前端也有越来越多的场景需要使用批跑脚本

  • 利用爬虫或者接口定时同步数据
  • 线上配置文件、数据文件定时批跑生成并发布到线上

切实的影响到业务,因此需要一套高可靠与及时告警的批跑管理系统。

node本身有丰富的npm模块,本模块的定时执行依赖于node-schedule模块(star 4300+)。


特性

  1. 高稳定性 (子进程调用任务,异常隔离)
  2. 弱侵入性 (任务迁移无改造成本)
  3. 可视化的web管理端 (任务与任务执行记录入库可视化管理,原理crontab管理烦恼)
  4. 便利的基础设施服务
    • 秒级定时批跑执行
    • 多语言支持 支持指定 执行器(node,bin/sh,php等) & 入口文件 (index.js, test.sh, index.php等)
    • 9类任务级别异常与敏感操作告警 & 框架执行异常告警
    • 任务执行产生的 日志文件&发布的文件 根据版本(YYYYMM/DD/HHMMSS)备份

接入使用

demo

可直接参见 example 目录下的例子(因为本系统为node编写而成,运行请先准备好node环境)

1. 安装

npm install tfschedule --save

2. 引入模块并输入参数

    // example/init.js
    var { TFSchedule } = require('tfschedule');
    var scheHandle = new TFSchedule({
        backExecRecordNum: 15, //  默认保存30天的任务执行记录,任务执行记录包括日志文件,发布文件的备份,执行记录的备份(存储在数据库中)
        mysqlConfig: { // mysql连接配置
            host: 'localhost',
            port: '3306',
            user: 'root',
            password: '1234',
            database: 'db_schedule' // 请先建立该数据库
        },
        taskRootPath: __dirname + '/task', // 任务脚本的根路径
        notifyList: '[email protected]',  // 默认的告警人员列表
    });
    // shell下执行运行
    node example/init.js

3. 启动web管理系统

web系统在8017端口打开,http://127.0.0.1:8017 推荐批跑与web系统分开启动,以避免互相影响。 部署到线上时建议通过ningx或者apapche配置反向代理,将某个前缀路径配置到本系统的端口。

    // example/initweb.js
    var { runWeb,webApp } = require('tfschedule');

    runWeb({
        mysqlConfig: {
            host: 'localhost',
            port: '3306',
            user: 'root',
            password: '1234',
            database: 'db_schedule'
        },
        taskRootPath: __dirname + '/task',
        port: 8017,
        oauthLogin: function () { // 授权登录的函数
            var MOCK_USER;
            if (process.env.NODE_ENV === 'production') {} else {
                MOCK_USER = {
                    LoginName: 'wilsonsliu', // 会读取此字段,记录相关人员使用web系统对任务进行的操作
                    ChineseName: '刘盛'
                };
                webApp.use(function (req, res, next) {
                    if (!res.locals) {res.locals = {};}
                    res.locals.userInfo = MOCK_USER;
                    next();
                });
            }
        }
    });

    // shell下运行,启动web系统
    node example/initweb.js

4. 新建任务文件

example/task目录下有个demo文件夹,以demo/node为例。

    var fs = require('fs-extra');
    var path = require('path');
    console.log('测试啦');
    fs.writeFileSync(path.join(__dirname,'publish','a.txt'),'sdsds'); // 写入publish目录,可自动备份版本

5. web系统新增任务

在web系统新增任务,例如如下配置。此时,批跑管理系统将按照设定的任务规则运行,每30S进行一次。

    {
        taskName: 'demo/node',
        rule: '*/30 * * * * *',
        owner: '[email protected];[email protected]', // 告警时的相关责任人
        title: '测试',
        description: '测试描述'
        command: 'node',
        entryFile: 'index.js',
    }

使用规范与细节

taskName && command && entryFile

TFSchedule规范任务名taskName唯一,一旦添加后,不建议更改(web端不提供入口)。

taskName为任务与taskRootPath的相对路径,建议最多不超过2级,否则不方便管理与查看,例如写为demo/node的方式,则执行路径变为demo/node/index.js

command即为任务的执行器,如果不设定则以 new TFSchedule(option)时传入的command为准。

entryFile即为任务入口文件,如果不设定则以 new TFSchedule(option)时传入的entryFile为准。

通过给任务指定不同的执行器与入口文件,我们可以将运行任何类型的语言任务。

任务退出码 exitCode

TFSchedule会监听子进程的close事件,close事件有2个参数exitCode, signalCode

exitCode即为退出码,当任务正常退出,则 exitCode 为0,进程因为未捕获的异常导致退出会接收到1。 在此之上,如果想手动执行退出,可调用process.exit(exitCode),建议通过自定义退出码达到更多的传送信息的目的。 目前建议使用100以上的退出码,0与1为node进程规范使用,2-100为TFSchedule预留的异常码。

singnalCodeprocess.kill(signalCode)传入,web系统下手动杀死执行中的任务即是调用这个方法进行杀死,手动杀死的异常码设置为2。

TFSchedule监听到非0的退出码会触发异常退出 closeError 告警,如果接收到signalCode会触发killTask敏感操作告警。

另外,存在exitCode为null的情况,即当任务尚在执行 or 任务进行中时遇到TFSchedule重启导致不再更新任务执行数据。

任务运行完,请及时退出

  1. 避免类似express一样起一个服务导致不退出
  2. 避免mysql连接未退出造成任务不退出

事件系统

TFSchedule继承了events.EventEmitter,目前暴露了如下事件可以绑定回调函数。

  TFSchedule.on('runTask', (taskName) => {});
  TFSchedule.on('taskStart', function ({ taskName, taskVersion }) {});
  TFSchedule.on('taskEnd', function ({ taskName, exitCode, taskVersion, errorLogList }) {});

  TFSchedule.on('taskLevelNotify', function({ type, title, content, taskName }){}); // type 即为 任务告警类型
  TFSchedule.on('systemError', function ({ errMsg, error }) {});
  // 告警最终将会通过 notify 事件触发,用户可以监听 notify 事件,在回调中调用自己的告警方法实现告警
  TFSchedule.on('notify', function ({ title, content,notifyList }) {});
}

系统设计与实现介绍

目录结构

以demo为例,task为任务的根目录,将所有任务集中在此目录下,每个任务的关键信息taskName、rule等则录入表t_task_list进行管理。

批跑系统去数据库中加载任务,遍历挂载执行。

taskName=demo/node这一条记录按照数据库中对应的rule进行挂在定时器,demo/node/index.js则为对应的任务入口文件,系统通过node task/demo/node/index.js执行任务。

├── example
│   ├── init.js // 初始化批跑系统
│   ├── initweb.js // 初始化批跑系统的web管理系统
│   └── task // 任务根路径
│       └── clearTaskExecRecord // 系统添加的任务:清理小助手,清理过期数据与文件
│       └── demo // demo测试
|           ├── shell // shell版本的demo
|           ├── node // node版本的demo
│               ├── history // 存放历史发布文件的版本
│               │   └── 201805 // 年月
│               │       └── 07 // 日期
│               │           ├── 123015 // HHmmss 精确到秒
│               │           │   └── gold_rate.json
│               ├── index.js // 任务执行文件,即 node index.js
│               ├── logs // 历史执行日志输出
│               │   └── 201805
│               │       └── 07
│               │           ├── 123015.log // 2018年5月7号12:30:15执行任务时,输出的日志
│               └── publish // 发布文件目录
│                   └── a.txt
└── src // 批跑系统源代码
    ├── index.js // 入口文件
    ├── lib // 库函数
    │   ├── execTask.js // 任务执行相关的函数
    │   ├── hook.js // 钩子函数 即 startExecTask, endExecTask 开始与结束时执行的函数
    │   ├── tpl.js // 保存数据库建表sql语句,以及任务clearTaskExecRecord的代码模版
    │   └── monitorHelper.js // 5个监控小助手
    │   ├── bindEvent.js // 绑定事件
    ├── public
    │   ├── index.html // web系统首页
    │   ├── lib // 依赖模块
    │   └── record.html // 执行记录页面
    └── webapp.js // web系统的入口文件

高稳定性

  1. 模块化,通用逻辑抽离
  2. 强化异常逻辑处理,并进行异常告警SystemError
  3. 子进程调用任务,异常隔离
  4. 兜底,pm2调用。任何系统都难以避免挂掉,如果系统挂掉则通过PM2自动重启任务。

弱侵入性

摒弃通过noderequire的方式加载对应的任务脚本,而是通过利用node子进程child_process.spawn的方式执行任务。并可以自己指定执行器与入口文件s

  1. 批跑脚本任务代码无需做任何改造,可以选择自己喜欢的方式去编写代码。
  2. 非通过noderequire的方式进行引入,每次任务更新时不需要重启批跑系统,只需要部署自己的任务的代码文件即可
  3. 多语言支持,而非仅能支持node

可视化的web管理端

  1. 通过表t_task_list来进行管理任务,主要录入每个任务的rule、timeout、lastStartTime、lastEndTime、lastWarningTime来实现任务的管理
  2. 通过表t_task_exec_list来记录任务执行记录,录入每一次执行过程的相关信息taskName,taskVersion,startTime,endTime,exitCode,warningTime,duration,errorLogs,publishFileList
  3. 通过可视化的WEB系统对任务以及执行记录进行管理

任务管理(新建、修改、切换任务状态) 任务执行列表,可以按照时间、任务名称、退出码进行筛选 异常日志查看与日志下载 历史版本文件查看

便利的基础设施服务

1. 秒级定时批跑执行

利用开源的node-schedule模块,该模块可完成类似crontab的功能,并且支持crontab的语法规则。主要用到scheduleJob这个接口进行定时任务挂载。

系统启动时,去数据库的t_task_list将所有任务的taskName、rule数据取出,并遍历进行挂载。同时,挂载后的句柄存储在scheduleJobs中。

    const {scheduleJob, scheduleJobs} = require('node-schedule');
    // 定时器的句柄会保存在scheduleJobs
    scheduleJob('test_node', '*/10 * * * * *', function () {
      // 触发 runTask事件,传送任务名称。 bindEvent.js中对runTask事件进行处理执行任务
      this.emit('runTask', taskName);
    });

2. 9类任务级别异常与敏感操作告警 & 框架执行异常告警

  • 任务级别的异常 taskLevelNotify
    1. entryFileIsNotExists 任务指定的入口文件不存在
    2. lastJobHasNotEnd 同一个任务的上次尚在执行未退出
    3. closeError exitCode非0,即异常退出(包括调用子进程时,触发error事件)
    4. outtimeTask 任务执行超时告警(t_task_list表中每个任务可指定超时时间为多少秒timeout)
    5. missrunTask 漏执行告警(cron-parser解析rule得到上次应该运行时间,通过与任务的lastStartTime比较确定是否漏执行)
  • 任务级别的敏感操作 taskLevelNotify
    1. killTask 任务在web系统主动杀死
    2. addTask 添加新任务
    3. modifyTask 任务运行规则修改
    4. taskDelete 数据库中任务被删除通知,理论上不允许删除操作(通过将目前挂载的任务scheduleJobs与数据库中任务进行比对,发现是否有任务被删除)
  • TFSchedule内被捕获的异常 systemError
  • TFSchedule系统启动通知 notify

3. 日志输出

父进程通过监听子进程的stdout,stderr两个输出流,得到子进程的日志输出。

日志将会存放在task/logs/YYYYMM/DD/HHmmss.log目录下,按照任务执行的时间存放,同时将stderr的信息入库(为保护批跑系统,做限制,只录入前50条),用以在UI界面展示与告警时输出。用户如果需要详细的日志还是需要查阅整个日志文件。

node中stderr可以通过console.error输出。另外如果进程异常退出也会输出到stderr,建议在catch住异常后通过console.error进行输出,再对异常进行处理。

4. 版本备份

除了日志以外,任务的执行过程中可能会产生一系列的文件,对于这些文件往往也也有进行版本备份的诉求。

每次任务执行的时候,可以将文件写入到对应任务的的publish目录,任务退出时,批跑系统会检测其publish是否为空,不为空则移动到history/YYYYMM/DD/HHmmss/目录下,并以版本号为文件夹存储,以方便备份查看。

建议:如果需要将文件发布上线可写一个通用模块方法进行调用

5. 监控小助手

TFSchedule挂载一个每3S执行一次的监控小助手,达到准实时监控的效果。

  • 小助手1:已存在的任务:数据库更新rule,cancel定时任务 并设置挂载新规则的定时任务;新增任务:按照rule进行挂载 addTask,modifyTask
  • 小助手2:用户设置taskStatus为2,则杀死当前进程,并更新taskStatus为1即任务无效 killTask
  • 小助手3:根据数据库中的timeout字段,进行超时提醒outtimeTask
  • 小助手4:任务漏执行,触发missrunTask
  • 小助手5:任务在数据库中被删除告警系统管理员deleteTask

6. 任务的初始化与结束

hook.js包含startExecTask, endExecTask两个函数在任务开始结束时运行。

startExecTask 执行如下动作

  • 置空任务的发布文件夹 task/taskName/publish
  • 更新任务表中的lastStartTime,taskVersion(任务的版本号根据运行时间生成const taskVersion = moment().format('YYYYMM/DD/HHmmss');)
  • 插入一条任务执行记录到t_task_exec_list

endExecTask执行如下动作

  • 设置退出的事件与退出码
  • 版本备份 :备份本次执行的发布文件夹task/taskName/publishtask/taskName/history/taskVersion
  • 更新任务运行记录(包括录入logs、发布的文件路径数组)

参考资料

  1. node-schedule
  2. 解析crontab的rule规则 cron-parser
  3. process对象与exitCode

tfschedule's People

Contributors

wilsonliu95 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

tfschedule's Issues

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.