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
相關文章
相關標籤/搜索