用agenda和agendash管理定時任務

在軟件系統的運維中,總有一些事件,須要在特定的時間來觸發執行,這個時候,咱們須要用到定時任務。javascript

agenda是nodejs實現的基於mongodb數據庫的分佈式定時任務管理系統。agendash則爲agenda提供了一個web管理控制檯。java

這篇文章,經過一個demo項目,演示瞭如何使用agenda來管理定時任務。node

爲何須要管理定時任務

最先用crontab管理來管理定時任務的時候,須要手動去服務器上設置任務,而後還要在服務器上部署定時執行的程序。整個過程依賴手工操做,用起來感受特別不踏實。那時候在想,應該有一種更方便的管理定時任務的機制,因此儘可能在設計上減小定時任務的使用,只在最必要的時候纔會使用。git

後來看了不少技術分享,看到知乎的分享他們的運維繫統的經驗,實現了一個能夠配置,而且有精美的管理後臺的定時任務管理系統,可以在運維後臺方便的對任務進行操做。es6

如今已經能夠簡單的使用agendash和agenda集成,就方便了實現了任務管理,從而能夠更專一的實現業務邏輯github

實現原理

雖然不須要本身再去發明輪子是很是方便的事情,可是仍是應該試着去本身動手作一些嘗試,實際實現起來成本比較高,可是思考一下如何實現,仍是有價值的。web

agenda經過mongodb實現了任務在定時任務處理集羣中的共享和鎖定,從而實現了分佈式執行定時任務的功能,實現了更高的可用性;mongodb

再結合做爲express插件開發的agendash,咱們就能夠經過管理後臺查詢和管理定時任務。docker

實現思路

若是我本身實現的話,首先要考慮定時任務如何設置,就是語法,agenda並無本身發明輪子,而是使用了已有的cron模塊,該模塊的定時任務配置語法,和crontab同樣,是形如*/5 * * * *的形式。shell

咱們要考慮的是定時任務的機制,程序執行以後,一直在進程中輪詢,是否符合觸發條件,若是符合觸發條件,就會觸發設置的要執行的業務邏輯相關代碼,crontab實際上也是觸發執行shell腳本的代碼。最後由業務邏輯代碼根據本身的實際狀況運行。

任務的調用,能夠用觀察者模式實現。在nodejs中,能夠方便的使用回調函數,將任務的名字和回調函數綁定,這樣,任務條件達到的時候,就會觸發執行回調函數;能夠結合nodejs的queue隊列模塊來實現。

只有把任務用專有的數據結構存儲起來,纔有可能實現某種任務自己的邏輯,須要什麼樣的邏輯,就須要什麼樣的數據結構作支撐。所以mongodb中要存儲的數據包括:執行條件、任務名稱、建立時間、上次開始時間、上次完成時間、下次執行時間、目前是否在鎖定狀態。

這樣,某個節點執行是,正好符合條件,它先設置任務狀態爲鎖定,而後調用回調函數,完成以後,在解除鎖定,而且設置相應的時間;若是出現程序意外崩潰,其餘節點檢查是否超過必定處理時間,會將任務的鎖定狀態解除,而後接下來的其餘節點,就會檢查而且執行任務。

使用agenda和agendash

agenda自己運行,是不須要web服務器;要使用agendash,目前必須安裝express,將agendash做爲插件添加到express中,就能夠正常的訪問。

演示程序的具體步驟以下:

  1. 安裝依賴包

  2. 搭建express腳手架

  3. 添加agenda任務和任務處理代碼

  4. 編寫簡單的測試

  5. 添加集成相關配置

安裝依賴包

項目須要用到的依賴包分爲三類,基本業務邏輯須要,es6編譯相關、還有測試依賴包。如下命令不包含babel相關依賴,請參看其餘網上的教程。

npm install --saveagenda agendash express mongoose ejs

npm install --save-dev mocha chai supertest

搭建express腳手架和agendash

import path from 'path'
import './config'
import {agendash } from './middlewares'

var express = require('express');
var app = express();
var router = express.Router();

app.set("view engine","ejs"); 
app.set('views', './views')
app.set("view options",{     "open":"{{",     "close":"}}"  });  

app.use(express.static('public'));
... ...
app.use('/agendash', agendash);
app.listen(8080, '0.0.0.0')

在express中經過app.use方法,能夠加載路由,agendash做爲一個插件,直接經過調用use方法,就能夠添加到express的路由中,項目中,將agendash的相關路由,添加到/agendash下,這樣的話,訪問地址就是http://localhost:8080/agendash/#

添加agenda任務和任務處理代碼

首先實例化一個agenda對象,設置mongodb數據庫鏈接地址,agenda會處理mongodb鏈接。

經過agenda實例的define方法,就能夠綁定事件和處理函數,第一個參數是事件名稱,第二個就是處理事件的回調函數;由於處理是過程是異步的,因此結束以後要調用done

agenda在初始化完成以後,會回調綁定的ready方法,在ready中,咱們就能夠調用agenda的every函數,建立新的定時任務。

將agenda實例做爲參數傳給Agendash,後者就會生成可以操做agenda實例的router。

var Agenda = require('agenda');
var Agendash = require('agendash');

var mongoConnectionString = config['agendaMongodbUrl']
var agenda = new Agenda({db: {address:mongoConnectionString}})

agenda.define('delete old users', function(job, done) {
  console.log("we will delete user here")
  done()
});

agenda.on('ready', function() {
  //agenda.every('3 minutes', 'delete old users');
  agenda.every('*/5 * * * *', 'delete old users');
  agenda.start();
});

export default Agendash(agenda)

編寫簡單的測試

完成編碼以後,咱們經過supertest編寫簡單測試,檢查是否能夠成功鏈接mongodb並啓動agendash;要成功運行測試,必須在本地安裝mongodb。

如代碼所示,咱們會測試鏈接agendash的api接口,檢查返回的json數據,是否符合咱們建立的定時任務。若是一致,那麼測試經過

const app = require('../lib')
const request = require('supertest');
var assert = require('assert');

describe('GET /agendash/api', function () {
  it('should return the correct overview', function (done) {
    request(app).get('/agendash/api')
    .expect(200)
    .expect(function (res) {
      assert(res.body.title, 'Agendash')
    })
    .end(done)
  })
})

添加集成相關配置

由於項目使用了es6語法,因此須要集成babel才能運行程序和測試。咱們在package.json中,添加start和test命令的script,在運行和測試的時候,都會用babel來實時編譯es6代碼。爲了成功的運行mocha測試,咱們還須要設置.babelrc配置文件。

# package.json
... ...
"scripts": {
    "start": "babel-node lib/index.js --presets es2015,stage-2",
    "test": "./node_modules/.bin/mocha --compilers js:babel-core/register ./test"
}

# .babelrc
{
  "presets": ["es2015","stage-2"],
  "plugins": []
}

... ...

# 而後咱們就能夠運行程序
npm install
npm start

若是不想本身安裝mongodb或者在本機安裝node_modules,項目的源代碼中提供了docker-compose配置文件,只須要運行docker-compose up命令,就能夠運行服務。而後打開瀏覽器查看http://localhost:8080/agendash

示例代碼 https://github.com/liuwill-projects/agenda-cron-demo

文/liuwill(簡書做者)
原文連接:用agenda和agendash管理定時任務著做權歸做者全部,轉載請聯繫做者得到受權,並標註「簡書做者」。

相關文章
相關標籤/搜索