schedule_task_monitor 前端批跑模块介绍

背景

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

前端也有愈来愈多的场景须要使用批跑脚本html

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

切实的影响到业务,所以须要一套高可靠与及时告警的批跑管理系统。前端

本文将批跑管理的系统封装为一个npm模块,能够方便使用,而且提供一套简单的web管理系统进行管理。java

如何使用

1.安装node

npm install schedule_task_monitor --save

gihub连接 https://github.com/WilsonLiu9...mysql

2.引入模块并输入参数linux

// init.js
var { run, eventEmitter, app } = require('sche_task_monitor');
run({
    mysql_config: { // mysql链接配置
        host: 'localhost',
        port: '3306',
        user: 'root',
        password: '1234',
        database: 'db_lct_schedule', // 请先创建该数据库
    },
    task_root_path: '/data/web/schedule/task/', // 任务脚本的根路径
    defaultRtx: 'wilsonsliu' // 告警默认传送对象
});
// 启动
node init.js

3.启动web管理系统git

web系统在8017端口打开: http://127.0.0.1:8017github

node  ./node_mudule/sche_task_monitor/webSystem/app.js

4.新建任务文件web

任务名称为test,此时须要可在/data/web/schedule/task/新建一个test目录,并新建/data/web/schedule/task/test/index.js;

var fs = require('fs-extra');
var path = require('path');
console.log('测试啦')
fs.writeFileSync(path.join(__dirname,'publish','a.txt'),'sdsds')

5.web系统新增任务
在web系统新增任务,例如以下配置

{
    task_name: 'test',
    rule: '*/30 * * * * *',
    rtx_list: 'wilsonliuxyz@gmail.com;test@qq.com', // 告警时的相关责任人
    title: '测试',
    description: '测试描述' 
}

此时,批跑管理系统将按照设定的任务规则运行,每15S进行一次。

事件系统

模块对外暴露了eventEmitter,能够经过监听task_start,task_end,notify事件来执行用户相应的代码。

eventEmitter.on('task_start', function ({ task_name, task_version }) {});
  // 任务结束
  eventEmitter.on('task_end', function ({ task_name, exit_code, task_version, error_log_list }) {});
  // 监听告警
  eventEmitter.on('notify', function ({ title, content, task_name,notify_list }) {});
}

注意的点

告警模块须要本身设计

经过监听notify事件来实现本身的告警。用户能够自行选择本身方便的方式,最好可以经过多类方式进行告警。例如微信,邮件,邮箱等等。达到高时效

notify若是没有task_name,那么notify_list,则使用初始化传入的defaultRtx进行。

发布批跑生成的文件

对于任务中生成的文件,规范放在对应的任务publish目录。实现本身的发布函数,在任务中进行调用。

任务退出码 exit_code

任务正常退出 批跑模块 会接受到 exit_code 为0,由于异常退出会接收到 1。当退出码为非0值时,将触发告警。用户能够经过process.exit(101),来触发告警

task_name设计

task_name惟一,且能够写为monitor/logline的方式,则执行路径变为monitor/logline/index.js。即入口文件为拼接的方式可多层级。不建议过深,不方便管理与查看。

非node批跑脚本?

对于非node的批跑脚本,咱们能够在入口文件中对其余脚本再次进行调用的方式进行既能够。

系统设计一览

定方向

利用crontab

说到批跑,第一个想到的确定是利用linux自带的crontab来完成定时批跑这一目的。
但依赖这种方式这样存在如下问题,

  1. 每一个任务都须要自行去crontab去新增一条规则,长此以往难以维护
  2. 任务执行的各类告警实现困难,漏执行,超时,异常退出等等

利用node开源的模块node-schedule

做为一个前端,固然是可以用JS实现的就所有就JS(node)来实现。

node自己有丰富的npm模块,node-schedule即是一个定时任务模块,有4300+的star。
你能够像crontab同样,编辑定时的rule,在rule指定的时间,会执行相应的回调函数。

  1. 经过表t_task_list来进行管理任务,主要录入每一个任务的rule、timeout、last_start_time、last_end_time、last_warning_time来实现任务的管理
  2. 经过批跑系通通一对任务管理与监控,以便对各类任务进行告警

定目标

批跑系统的目的是为了管理全部的批跑任务,而且对批跑任务进行监控。
同时,由于是会直接影响到线上的系统,因此在稳定性方面有高要求。

  1. 高稳定性
  2. 弱侵入性(尽可能减小批跑系统对相应任务的侵入)
  3. 便利的基础设施服务

    • 定时运行
    • 各类异常情形下进行告警
    • 日志输出
    • 版本备份
    • 任务执行数据入库与统计

定规范

task的入口脚本统一放在task目录进行管理,而每一个任务的关键信息task_name、rule等具体信息则录入表t_task_list,进行管理。

如下示例中task_name为gold,则批跑系统去数据库中找到task_name=gold这一条记录并按照,对应的rule进行挂在定时器,gold/index.js则为对应的任务入口文件,系统经过node task/gold/index.js执行特定任务。

src
├── index.js // 入口文件
├── lib
│   ├── execTask.js // 执行具体某个任务的代码
│   ├── hook.js // 开始与结束任务的钩子函数
│   ├── initDB.js // 初始化DB
│   └── monitorHelper.js // 5个监控小助手
├── webSystem // GUI的批跑管理系统
├── task // 指定该目录为任务根目录
|   └── gold // 具体某一个定时任务
|         └── index.js // 某一个任务的入口文件
|         └—— logs // 本任务留下的日志文件
│              └── 201711 // 某个月
│                  ├── 23_213854.log // 按照 day_HHmmss构建目录存放历史版本
|         └—— publish // 每次任务发布的文件夹,发布到线上须要手动调用发布函数,任务退出后批跑系统会自动将本目录下的文件备份到history目录
|         └—— history // 目录下文件按照 gold_profit.201711231015.json 即 name + time(精确到分钟) + 尾缀的形式保存
│              └── 201711 // 某一月份的历史发布文件
│                  ├── 23_213854 // 按照 day_HHmmss构建目录存放历史版本
│                  │   ├── currentYearPrice.json

web管理端展现

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

系统特性的介绍与原理简介

高稳定性

  1. 模块化、简单化。经过批跑系统模块化,并保证每一个模块代码精简与健壮,以此来提升批跑系统的稳定性。
  2. 批跑系统与任务隔离。批跑系统经过child_process.spawn子进程来运行任务,以保证批跑系统与具体任务之间进行隔离,任务的异常不会致使批跑系统的崩溃。
  3. 兜底,pm2管理。任何系统都难以免挂掉,若是系统挂掉则经过PM2自动重启任务。

弱侵入性

经过利用child_process.spawn的方式执行任务,规定task/task_name/index.js为任务的入口文件,至关于node task/task_name/index.js

优势:

  1. 批跑脚本任务代码无需作任何改造,能够选择本身喜欢的方式去编写代码。
  2. 非经过require的方式进行引入,每次任务更新时不须要重启批跑系统,只须要部署本身的任务的代码文件便可

须要注意的2点

  1. 任务不能够一直挂起,任务执行完成需退出。主要注意的检查项为mysql链接未关闭等。
  2. 批跑系统经过监放任务子进程的close事件,来了解任务是否执行完成。当exit_code为非0值时,批跑系统将进行告警(关于process.exit能够阅读文末的参考连接3)

    • 未catch住的异常致使的退出将会吐出exit_code=1catch住异常后,可经过process.exit(exit_code)来指定本身定义的exit_code(100之内为批跑系统保留状态码)
    • 子任务正常执行会吐出0

便利的基础设施服务

定时运行

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

系统启动时,去数据库的t_task_list将全部任务的task_name、rule数据取出,并遍历进行挂载。同时,挂载后的句柄存储在全局对象G_task_schedule_list

const schedule = require('node-schedule');
    // 全局保存任务定时器的句柄 G_task_schedule_list
    G_task_schedule_list[task_name] = schedule.scheduleJob(rule, function () {
      // 回调函数中执行具体的任务
      execTask(task_name, app);
    });

各类异常情形下进行告警

在如下5种状况时,对任务相关责任人进行告警。

  1. 任务执行超时告警(t_task_list表中每一个任务可指定超时时间为多少秒timeout)
  2. exit_code非0,即异常退出
  3. 漏执行告警(cron-parser解析rule获得上次应该运行时间,经过与任务的last_start_time比较肯定是否漏执行)
  4. 数据库中任务被删除通知(经过将目前挂载的任务G_task_schedule_list与数据库中任务进行比对,发现是否有任务被删除)
  5. 批跑模块内部异常

日志输出

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

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

stderr能够经过console.error输出,另外若是进程异常退出也会输出到stderr,建议在catch住异常后经过console.error进行输出。

版本备份

每次任务执行的时候,能够将文件写入到对应任务的的publish目录,若是须要发布上线能够手动调用Helper中的发布函数,针对目前部分强耦合于其余系统中的发布功能,能够以接口的形式批跑调用,并在接口中返回发布的内容,任务再将其写入publish目录以进行版本的备份。

每次任务退出后,批跑系统会检测其publish是否为空,不为空则移动到history目录目录下,并以版本号为文件夹存储,以方便备份查看。

监控小助手

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

  1. 小助手1:已存在的任务:数据库更新rule,cancel定时任务 并设置挂载新规则的定时任务;新增任务:按照rule进行挂载
  2. 小助手2:用户设置task_status为2,则杀死当前进程
  3. 小助手3:根据数据库中的timeout字段,进行超时提醒
  4. 小助手4:任务漏执行,告警通知
  5. 小助手5:任务在数据库中被删除告警用户

任务的初始化与结束

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

startExecTask 执行以下动做

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

endExecTask执行以下动做

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

小结

批跑系统做为一个基础设施与其余系统最大的不一样在于须要高稳定性且须要准确的监控告警以免任务出现各类状况致使线上问题,却后知后觉。

本系统的设计基本知足了设计目标,同时提供一套便于管理的web系统,能够方便的进行任务的管理,与历史执行状况的查看。

参考资料

  1. node-schedule
  2. 解析crontab的rule规则 cron-parser
  3. process对象与exit_code
相关文章
相关标签/搜索