随着node的出现与发展,前端承担了愈来愈多的职责。javascript
前端也有愈来愈多的场景须要使用批跑脚本html
切实的影响到业务,所以须要一套高可靠与及时告警的批跑管理系统。前端
本文将批跑管理的系统封装为一个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
为0,由于异常退出会接收到 1。当退出码为非0值时,将触发告警。用户能够经过process.exit(101)
,来触发告警
task_name惟一,且能够写为monitor/logline
的方式,则执行路径变为monitor/logline/index.js
。即入口文件为拼接的方式可多层级。不建议过深,不方便管理与查看。
对于非node的批跑脚本,咱们能够在入口文件中对其余脚本再次进行调用的方式进行既能够。
说到批跑,第一个想到的确定是利用linux自带的crontab来完成定时批跑这一目的。
但依赖这种方式这样存在如下问题,
做为一个前端,固然是可以用JS实现的就所有就JS(node)来实现。
node自己有丰富的npm模块,node-schedule
即是一个定时任务模块,有4300+的star。
你能够像crontab同样,编辑定时的rule,在rule指定的时间,会执行相应的回调函数。
rule、timeout、last_start_time、last_end_time、last_warning_time
来实现任务的管理批跑系统的目的是为了管理全部的批跑任务,而且对批跑任务进行监控。
同时,由于是会直接影响到线上的系统,因此在稳定性方面有高要求。
便利的基础设施服务
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
child_process.spawn
子进程来运行任务,以保证批跑系统与具体任务之间进行隔离,任务的异常不会致使批跑系统的崩溃。经过利用child_process.spawn
的方式执行任务,规定task/task_name/index.js
为任务的入口文件,至关于node task/task_name/index.js
。
优势:
require
的方式进行引入,每次任务更新时不须要重启批跑系统,只须要部署本身的任务的代码文件便可须要注意的2点
批跑系统经过监放任务子进程的close事件,来了解任务是否执行完成。当exit_code为非0值时,批跑系统将进行告警(关于process.exit
能够阅读文末的参考连接3)
exit_code=1
,catch
住异常后,可经过process.exit(exit_code)
来指定本身定义的exit_code
(100之内为批跑系统保留状态码)利用开源的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种状况时,对任务相关责任人进行告警。
t_task_list
表中每一个任务可指定超时时间为多少秒timeout
)exit_code
非0,即异常退出cron-parser
解析rule
获得上次应该运行时间,经过与任务的last_start_time
比较肯定是否漏执行)G_task_schedule_list
与数据库中任务进行比对,发现是否有任务被删除)父进程经过监听子进程的stdout,stderr
两个输出流,获得子进程的日志输出。
日志将会存放在task/logs/YYYYMM/DD/HHmmss.log
目录下,按照任务执行的时间存放,同时将stderr
的信息入库(为保护批跑系统,作限制,只录入前100条),用以在UI界面展现与告警时输出。用户若是须要详细的日志仍是须要查阅日志文件。
stderr
能够经过console.error
输出,另外若是进程异常退出也会输出到stderr,建议在catch住异常后经过console.error
进行输出。
每次任务执行的时候,能够将文件写入到对应任务的的publish
目录,若是须要发布上线能够手动调用Helper中的发布函数,针对目前部分强耦合于其余系统中的发布功能,能够以接口的形式批跑调用,并在接口中返回发布的内容,任务再将其写入publish
目录以进行版本的备份。
每次任务退出后,批跑系统会检测其publish
是否为空,不为空则移动到history
目录目录下,并以版本号为文件夹存储,以方便备份查看。
批跑系统挂载一个每3S执行一次的监控小助手,达到准实时监控的效果。
hook.js包含startExecTask, endExecTask两个函数在任务开始结束时运行。
startExecTask 执行以下动做
task/task_name/publish
last_start_time,task_version
(任务的版本号根据运行时间生成const task_version = moment().format('YYYYMM/DD/HHmmss');
)t_task_exec_list
endExecTask执行以下动做
task/task_name/publish
到task/task_name/history/task_version
批跑系统做为一个基础设施与其余系统最大的不一样在于须要高稳定性且须要准确的监控告警以免任务出现各类状况致使线上问题,却后知后觉。
本系统的设计基本知足了设计目标,同时提供一套便于管理的web系统,能够方便的进行任务的管理,与历史执行状况的查看。