thinknode
Version:
A fast, flexible and all-in-one web framework for node.js.
272 lines (216 loc) • 11 kB
JavaScript
'use strict';
exports.__esModule = true;
var _stringify = require('babel-runtime/core-js/json/stringify');
var _stringify2 = _interopRequireDefault(_stringify);
var _regenerator = require('babel-runtime/regenerator');
var _regenerator2 = _interopRequireDefault(_regenerator);
var _promise = require('babel-runtime/core-js/promise');
var _promise2 = _interopRequireDefault(_promise);
var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');
var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* 基于redis的简单定时任务。
* 通过订阅redis __keyevent@{db}__:expired事件来执行。
* 需要开启Redis Keyspace Notifications
* 修改redis配置notify-keyspace-events: 'Ex'
* @author richen
* @copyright Copyright (c) 2017 - <richenlin(at)gmail.com>
* @license MIT
* @version 2017/2/24
*/
var _class = function (_THINK$Base) {
(0, _inherits3.default)(_class, _THINK$Base);
function _class() {
(0, _classCallCheck3.default)(this, _class);
return (0, _possibleConstructorReturn3.default)(this, _THINK$Base.apply(this, arguments));
}
_class.prototype.init = function init(options) {
this.options = {
redis_host: options.redis_host || '127.0.0.1',
redis_port: options.redis_port || 6379,
redis_db: options.redis_db || '1',
redis_password: options.redis_password || '',
redis_timeout: null
};
this.prefix = 'THINKTASK';
};
_class.prototype.connect = function () {
var _ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee2() {
var key, self;
return _regenerator2.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
key = THINK.hash(this.options.redis_host + '_keyevent');
!THINK_CACHES.INSTANCES.REDISTASK && (THINK_CACHES.INSTANCES.REDISTASK = {});
if (!THINK_CACHES.INSTANCES.REDISTASK[key]) {
_context2.next = 4;
break;
}
return _context2.abrupt('return', _promise2.default.resolve(THINK_CACHES.INSTANCES.REDISTASK[key]));
case 4:
self = this;
return _context2.abrupt('return', THINK.await(key, (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee() {
var pub, sub;
return _regenerator2.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
THINK_CACHES.INSTANCES.REDISTASK[key] = {};
pub = THINK.adapter('RedisSocket', self.options);
sub = THINK.adapter('RedisSocket', self.options);
THINK_CACHES.INSTANCES.REDISTASK[key].INS = pub;
THINK_CACHES.INSTANCES.REDISTASK[key].TASK = {};
_context.next = 7;
return pub.connect();
case 7:
THINK_CACHES.INSTANCES.REDISTASK[key].PUB = pub.handle;
_context.next = 10;
return sub.connect();
case 10:
THINK_CACHES.INSTANCES.REDISTASK[key].SUB = sub.handle;
return _context.abrupt('return', THINK_CACHES.INSTANCES.REDISTASK[key]);
case 12:
case 'end':
return _context.stop();
}
}
}, _callee, this);
}))));
case 6:
case 'end':
return _context2.stop();
}
}
}, _callee2, this);
}));
function connect() {
return _ref.apply(this, arguments);
}
return connect;
}();
/**
* 定时任务
* @param cls
* @param fname
* @param args
* @param timeout
* @return {Promise.<void>}
*/
_class.prototype.task = function () {
var _ref3 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee3(cls, fname, args, timeout) {
var handle, cronValue, cronKey, info;
return _regenerator2.default.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
_context3.next = 2;
return this.trigger(cls, fname);
case 2:
_context3.next = 4;
return this.connect();
case 4:
handle = _context3.sent;
cronValue = args;
//非标量序列化
if (!THINK.isScalar(args)) {
cronValue = (0, _stringify2.default)(args);
}
cronKey = THINK.md5(cronValue);
//判断任务是否已经在队列中
_context3.next = 10;
return handle.INS.wrap('hget', [this.prefix + '_TASK_DATA', this.prefix + '_' + cronKey]).catch(function (e) {
THINK.log(e);
return '';
});
case 10:
info = _context3.sent;
if (info) {
_context3.next = 15;
break;
}
_context3.next = 14;
return handle.INS.wrap('hset', [this.prefix + '_TASK_DATA', this.prefix + '_' + cronKey, cronValue]).catch(function (e) {
THINK.log(e);
return null;
});
case 14:
return _context3.abrupt('return', handle.INS.wrap('setex', [this.prefix + '_' + cronKey, timeout, 1]));
case 15:
return _context3.abrupt('return', _promise2.default.resolve());
case 16:
case 'end':
return _context3.stop();
}
}
}, _callee3, this);
}));
function task(_x, _x2, _x3, _x4) {
return _ref3.apply(this, arguments);
}
return task;
}();
/**
* 监听
* @param cls
* @param fname
* @return {Promise.<T>}
*/
_class.prototype.trigger = function () {
var _ref4 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee4(cls, fname) {
var handle, self;
return _regenerator2.default.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
_context4.next = 2;
return this.connect();
case 2:
handle = _context4.sent;
self = this;
//查询订阅标志,防止多次订阅
if (!handle.TASK[self.options.redis_db]) {
//订阅redis __keyevent@{db}__:expired事件
handle.SUB.psubscribe('__keyevent@' + self.options.redis_db + '__:expired');
handle.TASK[self.options.redis_db] = 1;
//当接收到订阅消息调用对应服务
handle.SUB.on('pmessage', function (pattern, channel, expiredKey) {
return handle.INS.wrap('hget', [self.prefix + '_TASK_DATA', expiredKey]).then(function (data) {
var _args = [];
try {
// 解析函数参数
_args = JSON.parse(data);
} catch (e) {
return THINK.error(e);
}
//移除保存的数据
return handle.INS.wrap('hdel', [self.prefix + '_TASK_DATA', expiredKey]).then(function () {
//执行任务
return cls[fname](_args);
});
});
});
}
return _context4.abrupt('return', _promise2.default.resolve());
case 6:
case 'end':
return _context4.stop();
}
}
}, _callee4, this);
}));
function trigger(_x5, _x6) {
return _ref4.apply(this, arguments);
}
return trigger;
}();
return _class;
}(THINK.Base);
exports.default = _class;