const res = await ctx.curl('http://www.api.com/cache', { dataType: 'json', }); ctx.app.cache = res.data; }, };
|
這個(gè)定時(shí)任務(wù)會(huì)在每一個(gè) Worker 進(jìn)程上每 1 分鐘執(zhí)行一次,將遠(yuǎn)程數(shù)據(jù)請求回來掛載到 app.cache 上。
任務(wù)
- task 或 subscribe 同時(shí)支持 generator function 和 async function。
- task 的入?yún)?nbsp;ctx,匿名的 Context 實(shí)例,可以通過它調(diào)用 service 等。
定時(shí)方式
定時(shí)任務(wù)可以指定 interval 或者 cron 兩種不同的定時(shí)方式。
interval
通過 schedule.interval 參數(shù)來配置定時(shí)任務(wù)的執(zhí)行時(shí)機(jī),定時(shí)任務(wù)將會(huì)每間隔指定的時(shí)間執(zhí)行一次。interval 可以配置成
- 數(shù)字類型,單位為毫秒數(shù),例如 5000。
- 字符類型,會(huì)通過 ms 轉(zhuǎn)換成毫秒數(shù),例如 5s。
module.exports = { schedule: { // 每 10 秒執(zhí)行一次 interval: '10s', }, };
|
cron
通過 schedule.cron 參數(shù)來配置定時(shí)任務(wù)的執(zhí)行時(shí)機(jī),定時(shí)任務(wù)將會(huì)按照 cron 表達(dá)式在特定的時(shí)間點(diǎn)執(zhí)行。cron 表達(dá)式通過 cron-parser 進(jìn)行解析。
注意:cron-parser 支持可選的秒(linux crontab 不支持)。
* * * * * * ┬ ┬ ┬ ┬ ┬ ┬ │ │ │ │ │ | │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun) │ │ │ │ └───── month (1 - 12) │ │ │ └────────── day of month (1 - 31) │ │ └─────────────── hour (0 - 23) │ └──────────────────── minute (0 - 59) └───────────────────────── second (0 - 59, optional)
|
module.exports = { schedule: { // 每三小時(shí)準(zhǔn)點(diǎn)執(zhí)行一次 cron: '0 0 */3 * * *', }, };
|
類型
框架提供的定時(shí)任務(wù)默認(rèn)支持兩種類型,worker 和 all。worker 和 all 都支持上面的兩種定時(shí)方式,只是當(dāng)?shù)綀?zhí)行時(shí)機(jī)時(shí),會(huì)執(zhí)行定時(shí)任務(wù)的 worker 不同:
- worker 類型:每臺(tái)機(jī)器上只有一個(gè) worker 會(huì)執(zhí)行這個(gè)定時(shí)任務(wù),每次執(zhí)行定時(shí)任務(wù)的 worker 的選擇是隨機(jī)的。
- all 類型:每臺(tái)機(jī)器上的每個(gè) worker 都會(huì)執(zhí)行這個(gè)定時(shí)任務(wù)。
其他參數(shù)
除了剛才介紹到的幾個(gè)參數(shù)之外,定時(shí)任務(wù)還支持這些參數(shù):
- cronOptions: 配置 cron 的時(shí)區(qū)等,參見 cron-parser 文檔
- immediate:配置了該參數(shù)為 true 時(shí),這個(gè)定時(shí)任務(wù)會(huì)在應(yīng)用啟動(dòng)并 ready 后立刻執(zhí)行一次這個(gè)定時(shí)任務(wù)。
- disable:配置該參數(shù)為 true 時(shí),這個(gè)定時(shí)任務(wù)不會(huì)被啟動(dòng)。
- env:數(shù)組,僅在指定的環(huán)境下才啟動(dòng)該定時(shí)任務(wù)。
執(zhí)行日志
執(zhí)行日志會(huì)輸出到 ${appInfo.root}/logs/{app_name}/egg-schedule.log,默認(rèn)不會(huì)輸出到控制臺(tái),可以通過 config.customLogger.scheduleLogger 來自定義。
// config/config.default.js config.customLogger = { scheduleLogger: { // consoleLevel: 'NONE', // file: path.join(appInfo.root, 'logs', appInfo.name, 'egg-schedule.log'), }, };
|
動(dòng)態(tài)配置定時(shí)任務(wù)
有時(shí)候我們需要配置定時(shí)任務(wù)的參數(shù)。定時(shí)任務(wù)還有支持另一種寫法:
module.exports = app => { return { schedule: { interval: app.config.cacheTick, type: 'all', }, async task(ctx) { const res = await ctx.curl('http://www.api.com/cache', { contentType: 'json', }); ctx.app.cache = res.data; }, }; };
|
手動(dòng)執(zhí)行定時(shí)任務(wù)
我們可以通過 app.runSchedule(schedulePath) 來運(yùn)行一個(gè)定時(shí)任務(wù)。app.runSchedule 接受一個(gè)定時(shí)任務(wù)文件路徑(app/schedule 目錄下的相對路徑或者完整的絕對路徑),執(zhí)行對應(yīng)的定時(shí)任務(wù),返回一個(gè) Promise。
有一些場景我們可能需要手動(dòng)的執(zhí)行定時(shí)任務(wù),例如
- 通過手動(dòng)執(zhí)行定時(shí)任務(wù)可以更優(yōu)雅的編寫對定時(shí)任務(wù)的單元測試。
const mm = require('egg-mock'); const assert = require('assert');
it('should schedule work fine', async () => { const app = mm.app(); await app.ready(); await app.runSchedule('update_cache'); assert(app.cache); });
|
- 應(yīng)用啟動(dòng)時(shí),手動(dòng)執(zhí)行定時(shí)任務(wù)進(jìn)行系統(tǒng)初始化,等初始化完畢后再啟動(dòng)應(yīng)用。參見應(yīng)用啟動(dòng)自定義章節(jié),我們可以在 app.js 中編寫初始化邏輯。
module.exports = app => { app.beforeStart(async () => { // 保證應(yīng)用啟動(dòng)監(jiān)聽端口前數(shù)據(jù)已經(jīng)準(zhǔn)備好了 // 后續(xù)數(shù)據(jù)的更新由定時(shí)任務(wù)自動(dòng)觸發(fā) await app.runSchedule('update_cache'); }); };
|
擴(kuò)展定時(shí)任務(wù)類型
默認(rèn)框架提供的定時(shí)任務(wù)只支持每臺(tái)機(jī)器的單個(gè)進(jìn)程執(zhí)行和全部進(jìn)程執(zhí)行,有些情況下,我們的服務(wù)并不是單機(jī)部署的,這時(shí)候可能有一個(gè)集群的某一個(gè)進(jìn)程執(zhí)行一個(gè)定時(shí)任務(wù)的需求。
框架并沒有直接提供此功能,但開發(fā)者可以在上層框架自行擴(kuò)展新的定時(shí)任務(wù)類型。
在 agent.js 中繼承 agent.ScheduleStrategy,然后通過 agent.schedule.use() 注冊即可:
module.exports = agent => { class ClusterStrategy extends agent.ScheduleStrategy { start() { // 訂閱其他的分布式調(diào)度服務(wù)發(fā)送的消息,收到消息后讓一個(gè)進(jìn)程執(zhí)行定時(shí)任務(wù) // 用戶在定時(shí)任務(wù)的 schedule 配置中來配置分布式調(diào)度的場景(scene) agent.mq.subscribe(schedule.scene, () => this.sendOne()); } } agent.schedule.use('cluster', ClusterStrategy); };
|
ScheduleStrategy 基類提供了:
- schedule - 定時(shí)任務(wù)的屬性,disable 是默認(rèn)統(tǒng)一支持的,其他配置可以自行解析。
- this.sendOne(...args) - 隨機(jī)通知一個(gè) worker 執(zhí)行 task,args 會(huì)傳遞給 subscribe(...args) 或 task(ctx, ...args)。
- this.sendAll(...args) - 通知所有的 worker 執(zhí)行 task。
更多建議: