UNPKG

ticketman

Version:

A simple pull-based job/ticket system contians a centeral ticket dispatcher and distributed workers. This system is written in NodeJS, runing on MongoDB

217 lines (193 loc) 7.46 kB
// Generated by CoffeeScript 1.12.5 (function() { var DEFAULT_BASIC_AUTH, DEFAULT_TIMEOUT, DEFAULT_WATCH_INTERVAL, EventEmitter, PATH_FOR_REQUIRE_TICKET, TicketWorker, assert, debuglog, env, oauth, request, extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty; assert = require("assert"); oauth = require("./utils/oauth"); env = process.env.NODE_ENV || 'development'; DEFAULT_BASIC_AUTH = require('./config/config')[env]['basicAuth']; debuglog = require("debug")("ticketman:TicketWorker#"); EventEmitter = require('events').EventEmitter; request = require("request"); PATH_FOR_REQUIRE_TICKET = "/api/tickets/assign"; DEFAULT_TIMEOUT = 20 * 60 * 1000; DEFAULT_WATCH_INTERVAL = 1000; TicketWorker = (function(superClass) { extend(TicketWorker, superClass); function TicketWorker(options) { if (options == null) { options = {}; } assert((this.name = options.name), "missing id"); assert((this.id = options.id), "missing id"); assert((this.consumerSecret = options.consumer_secret || options.consumerSecret), "missing consumer secret"); assert((this.watchCategory = options.category), "missing category to watch"); assert((this.host = options.host), "missing host"); this.oauth = { consumer_key: this.id, consumer_secret: this.consumerSecret }; this._isBusy = false; this.timeout = options.timeout || DEFAULT_TIMEOUT; this.interval = options.interval || DEFAULT_WATCH_INTERVAL; this.basicAuth = options.basicAuth || DEFAULT_BASIC_AUTH; if (this.timeout < this.interval * 3) { this.timeout = this.interval * 3; } this.ticket = null; this.commenceAt = 0; debuglog("constructor, @name:" + this.name + ", @watchCategory:" + this.watchCategory + ", @timeout:" + this.timeout + ", @interval:" + this.interval); setInterval(((function(_this) { return function() { return _this.watch(); }; })(this)), this.interval); debuglog("[TicketWorker:constructor] @:%j", this); } TicketWorker.prototype.isBusy = function() { return this._isBusy; }; TicketWorker.prototype.watch = function() { debuglog("watch: isBusy:" + (this.isBusy())); if (this.isBusy()) { if (Date.now() > this.timeout + this.commenceAt) { this.giveup("ticket timeout"); } } else { this.requireTicket(); } }; TicketWorker.prototype.setBusy = function(val) { this._isBusy = Boolean(val); if (this._isBusy) { return this.commenceAt = Date.now(); } }; TicketWorker.prototype.requireTicket = function() { var body, options; debuglog("requireTicket"); if (this.isBusy()) { return; } this.setBusy(true); body = { category: this.watchCategory }; options = { method: 'PUT', auth: this.basicAuth, url: "" + this.host + PATH_FOR_REQUIRE_TICKET, headers: oauth.makeSignatureHeader(this.id, 'PUT', PATH_FOR_REQUIRE_TICKET, body, this.consumerSecret), json: body }; request(options, (function(_this) { return function(err, res, result) { debuglog("requireTicket: err:" + err + ", res.statusCode:" + (res != null ? res.statusCode : "n/a") + ", ticket:%j", (typeof ticket !== "undefined" && ticket !== null ? ticket.title + "(" + ticket._id + ")" : "n/a")); if (err != null) { return debuglog("requireTicket: err: " + err); } if (res.statusCode !== 200) { return debuglog("requireTicket: request failed, server status: " + res.statusCode); } if (result.success == null) { _this.setBusy(false); debuglog("requireTicket: request failed, " + result.error); return; } if (result.ticket == null) { _this.setBusy(false); debuglog("requireTicket: no more ticket"); return; } _this.ticket = result.ticket; if (_this.ticket._id) { _this.ticket.id = _this.ticket._id; } _this.emit("new ticket", _this.ticket); }; })(this)); return; }; TicketWorker.prototype.complete = function() { var _ticket, options, path; if (!this.isBusy()) { return; } path = "/api/tickets/" + this.ticket.id + "/complete"; options = { method: 'PUT', auth: this.basicAuth, headers: oauth.makeSignatureHeader(this.id, 'PUT', path, {}, this.consumerSecret), json: {}, url: "" + this.host + path }; request(options, function(err, res, ticket) { debuglog("complete: err:" + err + ", res.statusCode:" + (res != null ? res.statusCode : "n/a") + ", ticket:%j", (ticket != null ? ticket.title + "(" + ticket._id + ")" : "n/a")); }); _ticket = this.ticket; this.ticket = null; this.emit("complete", _ticket); this.setBusy(false); }; TicketWorker.prototype.update = function(message, kind) { var body, options, path; if (kind == null) { kind = 'default'; } if (this.ticket == null) { return debuglog("update: ERROR: current has no ticket. message:" + message); } body = { kind: kind, content: message }; path = "/api/tickets/" + this.ticket._id + "/comment"; options = { method: 'PUT', auth: this.basicAuth, headers: oauth.makeSignatureHeader(this.id, 'PUT', path, body, this.consumerSecret), url: "" + this.host + path, json: body }; request(options, function(err, res, ticket) { debuglog("update: err:" + err + ", res.statusCode:" + (res != null ? res.statusCode : "n/a") + ", ticket:%j", (ticket != null ? ticket.title + "(" + ticket._id + ")" : "n/a")); }); }; TicketWorker.prototype.giveup = function(reason) { var body, options, path; debuglog("giveup"); if (!this.isBusy()) { return; } if (this.ticket == null) { debuglog("ERROR: busy but not ticket!!!!"); this.setBusy(false); return; } path = "/api/tickets/" + this.ticket.id + "/giveup"; body = { reason: reason }; options = { method: 'PUT', auth: this.basicAuth, headers: oauth.makeSignatureHeader(this.id, 'PUT', path, body, this.consumerSecret), url: "" + this.host + path, json: body }; request(options, (function(_this) { return function(err, res, ticket) { var _ticket; debuglog("giveup: err:" + err + ", res.statusCode:" + (res != null ? res.statusCode : "n/a") + ", ticket:%j", (ticket != null ? ticket.title + "(" + ticket._id + ")" : "n/a")); _ticket = _this.ticket; _this.ticket = null; _this.emit("giveup", _ticket); _this.setBusy(false); }; })(this)); }; return TicketWorker; })(EventEmitter); module.exports = TicketWorker; }).call(this);