0、背景
在大型專案中,定時任務的應用場景越來越廣。一般來說,按照微服務的思想,我們會將定時任務單獨部署一套服務,核心的業務介面獨立到另一個服務中,從而降低相互之間的耦合程度。在需要使用定時任務時,只需要由定時任務微服務定時向核心業務服務發起非同步介面呼叫。
基於NodeJS來搭建這樣一套定時任務的話,我們可以使用現有比較成熟的第三方框架來快速搭建,開發人員只需要關注定時任務的實現邏輯即可。
1、agenda
在github搜尋nodejs schedule的話會有很多類庫,比如node-schedule,agenda,node-cron等。之所以選擇agenda的話主要由兩個原因:1、agenda介面簡單,還可使用人類可讀的cron表示式;2、agenda提供了完整的Restful API介面,以及可統計檢視操作的UI介面。
這樣的話,我們只要在程式碼中提前定義好定時任務處理邏輯,然後就可以在介面在新增或者移除定時任務安排,而無需重新上線。
下面我們就開始從頭搭建基於agenda的定時任務。
2、基礎環境準備
- MongoDB:agenda需要使用MongoDB來儲存定時任務資料。建議大家使用docker進行一建安裝,操作簡單,刪除也方便。只需要docker中搜尋mongo,選擇安裝預設推薦的官方版即可。
- agenda:定時任務管理框架,文件參考:https://github.com/agenda/agenda
- agendash:基於agenda的UI管理介面,文件參考:https://github.com/agenda/agendash
- express:用於配合agendash啟動WEB服務
- nirvana-logger:非必選,nodejs日誌輸出框架,文件參考:https://www.npmjs.com/package/nirvana-logger
3、樣例程式碼
1 // 框架引入 2 var express = require('express'); 3 var app = express(); 4 5 var Agenda = require('agenda'); 6 var Agendash = require('agendash'); 7 var L = require('nirvana-logger')('agenda') 8 9 // agenda初始化,並連線MongoDB 10 var agenda = new Agenda({db: {address: 'mongodb://localhost:32768/agenda'}}); 11 12 // 定義一個測試任務 13 agenda.define('testJob', function (job, done) { 14 try { 15 L('hello',job.attrs.data, new Date()) 16 done() 17 }catch (err) { 18 done(new Error(err)) 19 } 20 }) 21 22 // agenda框架啟動 23 agenda.on('ready', function () { 24 L("====>>>agenda啟動成功<<<<===") 25 agenda.start(); 26 }) 27 28 // Agendash UI介面 29 app.listen(3000); 30 app.use('/dash', Agendash(agenda));
13行:定義一個任務,名稱為testJob,後續我們可以通過該名字安排定時任務。第二個引數是一個函式,用於處理我們的業務邏輯,需要注意的是,我們需要在任務完成之後主動呼叫done方法,這樣agenda才會將任務標記為完成。
17行:如果任務執行過程中出現異常(比如網路請求異常)時,需要向done傳入一個error物件,agenda會將此任務標記為fail狀態。
23行:在agenda連線MongoDB成功後,會觸發ready的鉤子,我們才能在這裡開始安排定時任務,並且讓agenda開始執行定時任務掃描。
29行:在3000埠啟動express,同時使用agendash框架啟動agenda的WEB管理介面。
執行node命令啟動該js檔案,如果能在命令列看到“agenda啟動成功”則表示agenda連線資料庫成功並且成功啟動。
其實細心的同學可以,我們在上面的程式碼中只是定義了任務,但是並沒有對進行對任務進行定時執行。
所以接下來我們將演示如何在WEB介面上對定時任務進進行查詢,新增以及刪除的操作。
現在我們可以開啟:http://localhost:3000/dash/# 來檢視web介面。
4、定時任務介面管理
開啟agendash的預設介面是這樣
從介面上也可以看出,我們現在的確並未啟動任何定時任務。
4.1 新增定時任務
點選【Schedule job】,在後面彈出create job介面:
Job name:我們需要使用的任務名稱,即我們在程式中提前設定好的任務,比如剛才定義的testJob
Schedule:安排定時任務,這裡我們輸入希望定時任務執行的時間點,比如5 minutes。這裡時間的支援具體請參考:https://github.com/agenda/human-interval
Repeat every:迴圈執行定時任務,這裡輸入迴圈間隔時間。比如5 seconds。這裡需要注意的是schedule安排的任務只會執行一次,repeat任務會一直迴圈執行。所以這二者一般只需要按需求填一個即可。
Job data:向定時任務傳入的額外資料,我們可以在任務執行時通過job.attr.data獲取到這些引數。
點選儲存後,我們的定時任務就開始執行,可以看到控制檯開始迴圈執行列印日誌:
同時WEB介面資料將會更新,我們也能看到定時任務的執行狀態:
schedule安排一次性的定時任務也是類似的操作,大家可以自己嘗試。
值得注意的是,我們定義的任務,是可以被重複執行定時任務。
4.2 移除定時任務
點選某一個定時任務,就能檢視到任務的詳細資訊以及相關操作。
點選右上角的【delete selected】即可刪除該定時任務。
5、幾個注意點
- 定時任務的時間除了使用cron表示式以外,還只能簡單的英文表達,具體要參考https://github.com/agenda/human-interval
- 定時任務在執行過程中會將設定為鎖定狀態,任務執行完成以後再將任務鎖定狀態解除。所以如果任務在執行過程中,程式退出的話,那麼就會導致任務一直處於鎖定狀態,agenda預設10分鐘後自動解鎖任務。
- 為避免定時任務重複執行,一般來講定時任務微服務我們只需要部署一個例項即可。核心的業務介面處於負載均衡的考慮,可以按業務量多部署幾個例項。