pg-boss
Version:
Queueing jobs in Node.js using PostgreSQL like a boss
146 lines (110 loc) • 5.34 kB
JavaScript
'use strict';
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var EventEmitter = require('events');
var plans = require('./plans');
var events = {
error: 'error',
archived: 'archived',
deleted: 'deleted',
expired: 'expired',
monitorStates: 'monitor-states'
};
var Boss = function (_EventEmitter) {
_inherits(Boss, _EventEmitter);
function Boss(db, config) {
_classCallCheck(this, Boss);
var _this = _possibleConstructorReturn(this, (Boss.__proto__ || Object.getPrototypeOf(Boss)).call(this));
_this.db = db;
_this.config = config;
_this.timers = {};
_this.events = events;
_this.expireCommand = plans.expire(config.schema);
_this.archiveCommand = plans.archive(config.schema);
_this.purgeCommand = plans.purge(config.schema);
_this.countStatesCommand = plans.countStates(config.schema);
return _this;
}
_createClass(Boss, [{
key: 'supervise',
value: function supervise() {
var self = this;
// todo: add query that calcs avg start time delta vs. creation time
return Promise.all([monitor(this.archive, this.config.archiveCheckInterval), monitor(this.purge, this.config.deleteCheckInterval), monitor(this.expire, this.config.expireCheckInterval), this.config.monitorStateInterval ? monitor(this.countStates, this.config.monitorStateInterval) : null]);
function monitor(func, interval) {
return exec().then(repeat);
function exec() {
return func.call(self).catch(function (error) {
return self.emit(events.error, error);
});
}
function repeat() {
if (self.stopped) return;
self.timers[func.name] = setTimeout(function () {
return exec().then(repeat);
}, interval);
}
}
}
}, {
key: 'stop',
value: function stop() {
var _this2 = this;
if (this.stopped) return Promise.resolve();
this.stopped = true;
Object.keys(this.timers).forEach(function (key) {
return clearTimeout(_this2.timers[key]);
});
return Promise.resolve();
}
}, {
key: 'countStates',
value: function countStates() {
var _this3 = this;
var stateCountDefault = Object.assign({}, plans.states);
Object.keys(stateCountDefault).forEach(function (key) {
return stateCountDefault[key] = 0;
});
return this.db.executeSql(this.countStatesCommand).then(function (counts) {
var states = counts.rows.reduce(function (acc, item) {
if (item.name) acc.queues[item.name] = acc.queues[item.name] || Object.assign({}, stateCountDefault);
var queue = item.name ? acc.queues[item.name] : acc;
var state = item.state || 'all';
// parsing int64 since pg returns it as string
queue[state] = parseFloat(item.size);
return acc;
}, Object.assign({}, stateCountDefault, { queues: {} }));
_this3.emit(events.monitorStates, states);
return states;
});
}
}, {
key: 'expire',
value: function expire() {
var _this4 = this;
return this.db.executeSql(this.expireCommand).then(function (result) {
if (result.rowCount) _this4.emit(events.expired, result.rowCount);
});
}
}, {
key: 'archive',
value: function archive() {
var _this5 = this;
return this.db.executeSql(this.archiveCommand, [this.config.archiveCompletedJobsEvery]).then(function (result) {
if (result.rowCount) _this5.emit(events.archived, result.rowCount);
});
}
}, {
key: 'purge',
value: function purge() {
var _this6 = this;
return this.db.executeSql(this.purgeCommand, [this.config.deleteArchivedJobsEvery]).then(function (result) {
if (result.rowCount) _this6.emit(events.deleted, result.rowCount);
});
}
}]);
return Boss;
}(EventEmitter);
module.exports = Boss;