摘要:任務(wù)退出碼任務(wù)正常退出批跑模塊會(huì)接受到為,因?yàn)楫惓M顺鰰?huì)接收到。主要注意的檢查項(xiàng)為連接未關(guān)閉等。每次任務(wù)退出后,批跑系統(tǒng)會(huì)檢測(cè)其是否為空,不為空則移動(dòng)到目錄目錄下,并以版本號(hào)為文件夾存儲(chǔ),以方便備份查看。
背景
隨著node的出現(xiàn)與發(fā)展,前端承擔(dān)了越來(lái)越多的職責(zé)。
前端也有越來(lái)越多的場(chǎng)景需要使用批跑腳本
利用爬蟲或者接口定時(shí)同步數(shù)據(jù)到DB
線上配置文件、數(shù)據(jù)文件定時(shí)批跑生成并發(fā)布到線上
切實(shí)的影響到業(yè)務(wù),因此需要一套高可靠與及時(shí)告警的批跑管理系統(tǒng)。
本文將批跑管理的系統(tǒng)封裝為一個(gè)npm模塊,可以方便使用,并且提供一套簡(jiǎn)單的web管理系統(tǒng)進(jìn)行管理。
如何使用1.安裝
npm install schedule_task_monitor --save
gihub鏈接 https://github.com/WilsonLiu9...
2.引入模塊并輸入?yún)?shù)
// 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", // 請(qǐng)先建立該數(shù)據(jù)庫(kù) }, task_root_path: "/data/web/schedule/task/", // 任務(wù)腳本的根路徑 defaultRtx: "wilsonsliu" // 告警默認(rèn)傳送對(duì)象 }); // 啟動(dòng) node init.js
3.啟動(dòng)web管理系統(tǒng)
web系統(tǒng)在8017端口打開: http://127.0.0.1:8017
node ./node_mudule/sche_task_monitor/webSystem/app.js
4.新建任務(wù)文件
任務(wù)名稱為test,此時(shí)需要可在/data/web/schedule/task/新建一個(gè)test目錄,并新建/data/web/schedule/task/test/index.js;
var fs = require("fs-extra"); var path = require("path"); console.log("測(cè)試?yán)?) fs.writeFileSync(path.join(__dirname,"publish","a.txt"),"sdsds")
5.web系統(tǒng)新增任務(wù)
在web系統(tǒng)新增任務(wù),例如如下配置
{ task_name: "test", rule: "*/30 * * * * *", rtx_list: "wilsonliuxyz@gmail.com;test@qq.com", // 告警時(shí)的相關(guān)責(zé)任人 title: "測(cè)試", description: "測(cè)試描述" }
此時(shí),批跑管理系統(tǒng)將按照設(shè)定的任務(wù)規(guī)則運(yùn)行,每15S進(jìn)行一次。
事件系統(tǒng)模塊對(duì)外暴露了eventEmitter,可以通過(guò)監(jiān)聽task_start,task_end,notify事件來(lái)執(zhí)行用戶相應(yīng)的代碼。
eventEmitter.on("task_start", function ({ task_name, task_version }) {}); // 任務(wù)結(jié)束 eventEmitter.on("task_end", function ({ task_name, exit_code, task_version, error_log_list }) {}); // 監(jiān)聽告警 eventEmitter.on("notify", function ({ title, content, task_name,notify_list }) {}); }注意的點(diǎn) 告警模塊需要自己設(shè)計(jì)
通過(guò)監(jiān)聽notify事件來(lái)實(shí)現(xiàn)自己的告警。用戶可以自行選擇自己方便的方式,最好能夠通過(guò)多類方式進(jìn)行告警。例如微信,郵件,郵箱等等。達(dá)到高時(shí)效
notify如果沒(méi)有task_name,那么notify_list,則使用初始化傳入的defaultRtx進(jìn)行。
發(fā)布批跑生成的文件對(duì)于任務(wù)中生成的文件,規(guī)范放在對(duì)應(yīng)的任務(wù)publish目錄。實(shí)現(xiàn)自己的發(fā)布函數(shù),在任務(wù)中進(jìn)行調(diào)用。
任務(wù)退出碼 exit_code任務(wù)正常退出 批跑模塊 會(huì)接受到 exit_code 為0,因?yàn)楫惓M顺鰰?huì)接收到 1。當(dāng)退出碼為非0值時(shí),將觸發(fā)告警。用戶可以通過(guò)process.exit(101),來(lái)觸發(fā)告警
task_name設(shè)計(jì)task_name唯一,且可以寫為monitor/logline的方式,則執(zhí)行路徑變?yōu)?b>monitor/logline/index.js。即入口文件為拼接的方式可多層級(jí)。不建議過(guò)深,不方便管理與查看。
非node批跑腳本?對(duì)于非node的批跑腳本,我們可以在入口文件中對(duì)其他腳本再次進(jìn)行調(diào)用的方式進(jìn)行既可以。
系統(tǒng)設(shè)計(jì)一覽 定方向 利用crontab說(shuō)到批跑,第一個(gè)想到的肯定是利用linux自帶的crontab來(lái)完成定時(shí)批跑這一目的。
但依賴這種方式這樣存在以下問(wèn)題,
每個(gè)任務(wù)都需要自行去crontab去新增一條規(guī)則,久而久之難以維護(hù)
任務(wù)執(zhí)行的各種告警實(shí)現(xiàn)困難,漏執(zhí)行,超時(shí),異常退出等等
利用node開源的模塊node-schedule作為一個(gè)前端,當(dāng)然是能夠用JS實(shí)現(xiàn)的就全部就JS(node)來(lái)實(shí)現(xiàn)。
node本身有豐富的npm模塊,node-schedule便是一個(gè)定時(shí)任務(wù)模塊,有4300+的star。
你可以像crontab一樣,編輯定時(shí)的rule,在rule指定的時(shí)間,會(huì)執(zhí)行相應(yīng)的回調(diào)函數(shù)。
通過(guò)表t_task_list來(lái)進(jìn)行管理任務(wù),主要錄入每個(gè)任務(wù)的rule、timeout、last_start_time、last_end_time、last_warning_time來(lái)實(shí)現(xiàn)任務(wù)的管理
通過(guò)批跑系統(tǒng)統(tǒng)一對(duì)任務(wù)管理與監(jiān)控,以便對(duì)各種任務(wù)進(jìn)行告警
定目標(biāo)批跑系統(tǒng)的目的是為了管理所有的批跑任務(wù),并且對(duì)批跑任務(wù)進(jìn)行監(jiān)控。
同時(shí),因?yàn)槭菚?huì)直接影響到線上的系統(tǒng),所以在穩(wěn)定性方面有高要求。
高穩(wěn)定性
弱侵入性(盡量減少批跑系統(tǒng)對(duì)相應(yīng)任務(wù)的侵入)
便利的基礎(chǔ)設(shè)施服務(wù)
定時(shí)運(yùn)行
各種異常情形下進(jìn)行告警
日志輸出
版本備份
任務(wù)執(zhí)行數(shù)據(jù)入庫(kù)與統(tǒng)計(jì)
定規(guī)范task的入口腳本統(tǒng)一放在task目錄進(jìn)行管理,而每個(gè)任務(wù)的關(guān)鍵信息task_name、rule等具體信息則錄入表t_task_list,進(jìn)行管理。
以下示例中task_name為gold,則批跑系統(tǒng)去數(shù)據(jù)庫(kù)中找到task_name=gold這一條記錄并按照,對(duì)應(yīng)的rule進(jìn)行掛在定時(shí)器,gold/index.js則為對(duì)應(yīng)的任務(wù)入口文件,系統(tǒng)通過(guò)node task/gold/index.js執(zhí)行特定任務(wù)。
src ├── index.js // 入口文件 ├── lib │ ├── execTask.js // 執(zhí)行具體某個(gè)任務(wù)的代碼 │ ├── hook.js // 開始與結(jié)束任務(wù)的鉤子函數(shù) │ ├── initDB.js // 初始化DB │ └── monitorHelper.js // 5個(gè)監(jiān)控小助手 ├── webSystem // GUI的批跑管理系統(tǒng) ├── task // 指定該目錄為任務(wù)根目錄 | └── gold // 具體某一個(gè)定時(shí)任務(wù) | └── index.js // 某一個(gè)任務(wù)的入口文件 | └—— logs // 本任務(wù)留下的日志文件 │ └── 201711 // 某個(gè)月 │ ├── 23_213854.log // 按照 day_HHmmss構(gòu)建目錄存放歷史版本 | └—— publish // 每次任務(wù)發(fā)布的文件夾,發(fā)布到線上需要手動(dòng)調(diào)用發(fā)布函數(shù),任務(wù)退出后批跑系統(tǒng)會(huì)自動(dòng)將本目錄下的文件備份到history目錄 | └—— history // 目錄下文件按照 gold_profit.201711231015.json 即 name + time(精確到分鐘) + 尾綴的形式保存 │ └── 201711 // 某一月份的歷史發(fā)布文件 │ ├── 23_213854 // 按照 day_HHmmss構(gòu)建目錄存放歷史版本 │ │ ├── currentYearPrice.jsonweb管理端展示
模塊化、簡(jiǎn)單化。通過(guò)批跑系統(tǒng)模塊化,并保證每個(gè)模塊代碼精簡(jiǎn)與健壯,以此來(lái)提高批跑系統(tǒng)的穩(wěn)定性。
批跑系統(tǒng)與任務(wù)隔離。批跑系統(tǒng)通過(guò)child_process.spawn子進(jìn)程來(lái)運(yùn)行任務(wù),以保證批跑系統(tǒng)與具體任務(wù)之間進(jìn)行隔離,任務(wù)的異常不會(huì)導(dǎo)致批跑系統(tǒng)的崩潰。
兜底,pm2管理。任何系統(tǒng)都難以避免掛掉,如果系統(tǒng)掛掉則通過(guò)PM2自動(dòng)重啟任務(wù)。
弱侵入性通過(guò)利用child_process.spawn的方式執(zhí)行任務(wù),規(guī)定task/task_name/index.js為任務(wù)的入口文件,相當(dāng)于node task/task_name/index.js。
優(yōu)點(diǎn):
批跑腳本任務(wù)代碼無(wú)需做任何改造,可以選擇自己喜歡的方式去編寫代碼。
非通過(guò)require的方式進(jìn)行引入,每次任務(wù)更新時(shí)不需要重啟批跑系統(tǒng),只需要部署自己的任務(wù)的代碼文件即可
需要注意的2點(diǎn)
任務(wù)不可以一直掛起,任務(wù)執(zhí)行完成需退出。主要注意的檢查項(xiàng)為mysql連接未關(guān)閉等。
批跑系統(tǒng)通過(guò)監(jiān)聽任務(wù)子進(jìn)程的close事件,來(lái)了解任務(wù)是否執(zhí)行完成。當(dāng)exit_code為非0值時(shí),批跑系統(tǒng)將進(jìn)行告警(關(guān)于process.exit可以閱讀文末的參考鏈接3)
未catch住的異常導(dǎo)致的退出將會(huì)吐出exit_code=1,catch住異常后,可通過(guò)process.exit(exit_code)來(lái)指定自己定義的exit_code(100以內(nèi)為批跑系統(tǒng)保留狀態(tài)碼)
子任務(wù)正常執(zhí)行會(huì)吐出0
便利的基礎(chǔ)設(shè)施服務(wù) 定時(shí)運(yùn)行利用開源的node-schedule模塊,該模塊可完成類似crontab的功能,并且支持crontab的語(yǔ)法規(guī)則。主要用到scheduleJob這個(gè)接口進(jìn)行定時(shí)任務(wù)掛載。
系統(tǒng)啟動(dòng)時(shí),去數(shù)據(jù)庫(kù)的t_task_list將所有任務(wù)的task_name、rule數(shù)據(jù)取出,并遍歷進(jìn)行掛載。同時(shí),掛載后的句柄存儲(chǔ)在全局對(duì)象G_task_schedule_list。
const schedule = require("node-schedule"); // 全局保存任務(wù)定時(shí)器的句柄 G_task_schedule_list G_task_schedule_list[task_name] = schedule.scheduleJob(rule, function () { // 回調(diào)函數(shù)中執(zhí)行具體的任務(wù) execTask(task_name, app); });各種異常情形下進(jìn)行告警
在以下5種情況時(shí),對(duì)任務(wù)相關(guān)責(zé)任人進(jìn)行告警。
任務(wù)執(zhí)行超時(shí)告警(t_task_list表中每個(gè)任務(wù)可指定超時(shí)時(shí)間為多少秒timeout)
exit_code非0,即異常退出
漏執(zhí)行告警(cron-parser解析rule得到上次應(yīng)該運(yùn)行時(shí)間,通過(guò)與任務(wù)的last_start_time比較確定是否漏執(zhí)行)
數(shù)據(jù)庫(kù)中任務(wù)被刪除通知(通過(guò)將目前掛載的任務(wù)G_task_schedule_list與數(shù)據(jù)庫(kù)中任務(wù)進(jìn)行比對(duì),發(fā)現(xiàn)是否有任務(wù)被刪除)
批跑模塊內(nèi)部異常
日志輸出父進(jìn)程通過(guò)監(jiān)聽子進(jìn)程的stdout,stderr兩個(gè)輸出流,得到子進(jìn)程的日志輸出。
日志將會(huì)存放在task/logs/YYYYMM/DD/HHmmss.log目錄下,按照任務(wù)執(zhí)行的時(shí)間存放,同時(shí)將stderr的信息入庫(kù)(為保護(hù)批跑系統(tǒng),做限制,只錄入前100條),用以在UI界面展示與告警時(shí)輸出。用戶如果需要詳細(xì)的日志還是需要查閱日志文件。
stderr可以通過(guò)console.error輸出,另外如果進(jìn)程異常退出也會(huì)輸出到stderr,建議在catch住異常后通過(guò)console.error進(jìn)行輸出。
版本備份每次任務(wù)執(zhí)行的時(shí)候,可以將文件寫入到對(duì)應(yīng)任務(wù)的的publish目錄,如果需要發(fā)布上線可以手動(dòng)調(diào)用Helper中的發(fā)布函數(shù),針對(duì)目前部分強(qiáng)耦合于其他系統(tǒng)中的發(fā)布功能,可以以接口的形式批跑調(diào)用,并在接口中返回發(fā)布的內(nèi)容,任務(wù)再將其寫入publish目錄以進(jìn)行版本的備份。
每次任務(wù)退出后,批跑系統(tǒng)會(huì)檢測(cè)其publish是否為空,不為空則移動(dòng)到history目錄目錄下,并以版本號(hào)為文件夾存儲(chǔ),以方便備份查看。
監(jiān)控小助手批跑系統(tǒng)掛載一個(gè)每3S執(zhí)行一次的監(jiān)控小助手,達(dá)到準(zhǔn)實(shí)時(shí)監(jiān)控的效果。
小助手1:已存在的任務(wù):數(shù)據(jù)庫(kù)更新rule,cancel定時(shí)任務(wù) 并設(shè)置掛載新規(guī)則的定時(shí)任務(wù);新增任務(wù):按照rule進(jìn)行掛載
小助手2:用戶設(shè)置task_status為2,則殺死當(dāng)前進(jìn)程
小助手3:根據(jù)數(shù)據(jù)庫(kù)中的timeout字段,進(jìn)行超時(shí)提醒
小助手4:任務(wù)漏執(zhí)行,告警通知
小助手5:任務(wù)在數(shù)據(jù)庫(kù)中被刪除告警用戶
任務(wù)的初始化與結(jié)束hook.js包含startExecTask, endExecTask兩個(gè)函數(shù)在任務(wù)開始結(jié)束時(shí)運(yùn)行。
startExecTask 執(zhí)行如下動(dòng)作
置空任務(wù)的發(fā)布文件夾 task/task_name/publish
更新任務(wù)表中的last_start_time,task_version(任務(wù)的版本號(hào)根據(jù)運(yùn)行時(shí)間生成const task_version = moment().format("YYYYMM/DD/HHmmss");)
插入一條任務(wù)執(zhí)行記錄到t_task_exec_list
endExecTask執(zhí)行如下動(dòng)作
設(shè)置退出的事件與退出碼
版本備份 :備份本次執(zhí)行的發(fā)布文件夾task/task_name/publish到task/task_name/history/task_version
更新任務(wù)運(yùn)行記錄(包括錄入logs、發(fā)布的文件路徑數(shù)組)
小結(jié)批跑系統(tǒng)作為一個(gè)基礎(chǔ)設(shè)施與其他系統(tǒng)最大的不同在于需要高穩(wěn)定性且需要準(zhǔn)確的監(jiān)控告警以避免任務(wù)出現(xiàn)各種情況導(dǎo)致線上問(wèn)題,卻后知后覺(jué)。
本系統(tǒng)的設(shè)計(jì)基本滿足了設(shè)計(jì)目標(biāo),同時(shí)提供一套便于管理的web系統(tǒng),可以方便的進(jìn)行任務(wù)的管理,與歷史執(zhí)行情況的查看。
參考資料node-schedule
解析crontab的rule規(guī)則 cron-parser
process對(duì)象與exit_code
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/94177.html
摘要:延伸閱讀學(xué)習(xí)與實(shí)踐資料索引與前端工程化實(shí)踐前端每周清單半年盤點(diǎn)之篇前端每周清單半年盤點(diǎn)之與篇前端每周清單半年盤點(diǎn)之篇 前端每周清單專注前端領(lǐng)域內(nèi)容,以對(duì)外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點(diǎn);分為新聞熱點(diǎn)、開發(fā)教程、工程實(shí)踐、深度閱讀、開源項(xiàng)目、巔峰人生等欄目。歡迎關(guān)注【前端之巔】微信公眾號(hào)(ID:frontshow),及時(shí)獲取前端每周清單;本文則是對(duì)于半年來(lái)發(fā)布的前端每周清單...
摘要:廣義的定位,涉及到瀏覽器,手機(jī)里面的用戶交互展示的內(nèi)容,都屬于前端。對(duì)自己有好處因?yàn)槎啻魏桶⒗锏拿嬖嚬龠M(jìn)行了電話面試溝通,所以這些不只是一個(gè)面試官提出的問(wèn)題,而是多個(gè)面試官提出的問(wèn)題。保持一個(gè)虛心學(xué)習(xí)的狀態(tài)。 介紹 狹義的來(lái)講,前端指的就是我們常說(shuō)的html, css, javascript. 三者必不可缺. 而其中涵蓋的知識(shí)點(diǎn)不可一篇文章就能完整的講述出來(lái)的。廣義的定位,涉及到瀏覽器...
摘要:前端每周清單專注前端領(lǐng)域內(nèi)容,以對(duì)外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點(diǎn)分為新聞熱點(diǎn)開發(fā)教程工程實(shí)踐深度閱讀開源項(xiàng)目巔峰人生等欄目。對(duì)該漏洞的綜合評(píng)級(jí)為高危。目前,相關(guān)利用方式已經(jīng)在互聯(lián)網(wǎng)上公開,近期出現(xiàn)攻擊嘗試爆發(fā)的可能。 前端每周清單專注前端領(lǐng)域內(nèi)容,以對(duì)外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點(diǎn);分為新聞熱點(diǎn)、開發(fā)教程、工程實(shí)踐、深度閱讀、開源項(xiàng)目、巔峰人生等欄目。歡...
摘要:又將整個(gè)文藝類閱讀系統(tǒng)的業(yè)務(wù)劃分為兩大部分,分別是面向管理員和合作作者的后臺(tái)管理系統(tǒng)和面向用戶的移動(dòng)端,系統(tǒng)的需求分析將圍繞這兩部分進(jìn)行展開。 效果展示 showImg(https://user-gold-cdn.xitu.io/2018/8/26/16576a709bd02f5f?w=1409&h=521&f=gif&s=30128195); showImg(https://user...
閱讀 3038·2021-11-25 09:43
閱讀 3674·2021-11-24 11:13
閱讀 3436·2021-10-14 09:42
閱讀 2651·2021-09-23 11:53
閱讀 3678·2021-09-22 15:57
閱讀 3288·2021-09-02 09:54
閱讀 3557·2019-08-30 13:47
閱讀 1694·2019-08-29 16:55