用agenda和agendash管理定时任务

在软件系统的运维中,总有一些事件,需要在特定的时间来触发执行,这个时候,我们需要用到定时任务。

agenda是nodejs实现的基于mongodb数据库的分布式定时任务管理系统。agendash则为agenda提供了一个web管理控制台。

这篇文章,通过一个demo项目,演示了如何使用agenda来管理定时任务。

为什么需要管理定时任务

最早用crontab管理来管理定时任务的时候,需要手动去服务器上设置任务,然后还要在服务器上部署定时执行的程序。整个过程依赖手工操作,用起来感觉特别不踏实。那时候在想,应该有一种更方便的管理定时任务的机制,所以尽量在设计上减少定时任务的使用,只在最必要的时候才会使用。

后来看了很多技术分享,看到知乎的分享他们的运维系统的经验,实现了一个可以配置,并且有精美的管理后台的定时任务管理系统,能够在运维后台方便的对任务进行操作。

现在已经可以简单的使用agendash和agenda集成,就方便了实现了任务管理,从而可以更专注的实现业务逻辑

实现原理

虽然不需要自己再去发明轮子是非常方便的事情,但是还是应该试着去自己动手做一些尝试,实际实现起来成本比较高,但是思考一下如何实现,还是有价值的。

agenda通过mongodb实现了任务在定时任务处理集群中的共享和锁定,从而实现了分布式执行定时任务的功能,实现了更高的可用性;

再结合作为express插件开发的agendash,我们就可以通过管理后台查询和管理定时任务。

实现思路

如果我自己实现的话,首先要考虑定时任务如何设置,就是语法,agenda并没有自己发明轮子,而是使用了已有的cron模块,该模块的定时任务配置语法,和crontab一样,是形如*/5 * * * *的形式。

我们要考虑的是定时任务的机制,程序执行之后,一直在进程中轮询,是否符合触发条件,如果符合触发条件,就会触发设置的要执行的业务逻辑相关代码,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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,568评论 25 707
  • 在 node 的一些小型项目中我们可以使用 Agenda 模块来完成定时任务。从个人角度上来说并不建议使用 nod...
    点融黑帮阅读 6,775评论 0 8
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,359评论 6 343
  • “金无足赤,人无完人”,然而当面对自己缺点的时候,并不是所有人都能那样坦然了;如果要勇敢地暴露自身缺点,对大多数人...
    晓雪Eileen阅读 608评论 0 0
  • 孩子的行为、思维、心理与其生活的环境有密切的影响,在安全的需要、爱的需要得到满的情况下,孩子的发展一般是积极、乐观...
    稼轩李德智阅读 900评论 0 0