UNPKG

coffee-resque

Version:
281 lines (244 loc) 8.48 kB
// Generated by CoffeeScript 1.4.0 (function() { var Connection, EventEmitter, Worker, connectToRedis, __slice = [].slice, __hasProp = {}.hasOwnProperty, __extends = 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; }; exports.version = '0.1.11'; exports.connect = function(options) { return new exports.Connection(options || {}); }; EventEmitter = require('events').EventEmitter; Connection = (function() { function Connection(options) { this.redis = options.redis || connectToRedis(options); this.namespace = options.namespace || 'resque'; this.callbacks = options.callbacks || {}; this.timeout = options.timeout || 5000; if (options.database != null) { this.redis.select(options.database); } } Connection.prototype.enqueue = function(queue, func, args, callback) { var _ref; if (typeof args === 'function') { _ref = [args, []], callback = _ref[0], args = _ref[1]; } this.redis.sadd(this.key('queues'), queue); return this.redis.rpush(this.key('queue', queue), JSON.stringify({ "class": func, args: args || [] }), callback); }; Connection.prototype.worker = function(queues, callbacks) { return new exports.Worker(this, queues, callbacks || this.callbacks); }; Connection.prototype.end = function() { return this.redis.quit(); }; Connection.prototype.key = function() { var args; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; args.unshift(this.namespace); return args.join(":"); }; return Connection; })(); Worker = (function(_super) { __extends(Worker, _super); function Worker(connection, queues, callbacks) { this.conn = connection; this.redis = connection.redis; this.queues = queues; this.callbacks = callbacks || {}; this.running = false; this.ready = false; this.checkQueues(); } Worker.prototype.start = function() { var _this = this; if (this.ready) { return this.init(function() { return _this.poll(); }); } else { return this.running = true; } }; Worker.prototype.end = function(cb) { this.running = false; this.untrack(); return this.redis.del([this.conn.key('worker', this.name), this.conn.key('worker', this.name, 'started'), this.conn.key('stat', 'failed', this.name), this.conn.key('stat', 'processed', this.name)], cb || function() {}); }; Worker.prototype.poll = function(title, nQueue) { var _this = this; if (nQueue == null) { nQueue = 0; } if (!this.running) { return; } if (title) { process.title = title; } this.queue = this.queues[nQueue]; this.emit('poll', this, this.queue); return this.redis.lpop(this.conn.key('queue', this.queue), function(err, resp) { if (!err && resp) { return _this.perform(JSON.parse(resp.toString())); } else { if (err) { _this.emit('error', err, _this, _this.queue); } if (nQueue === _this.queues.length - 1) { return process.nextTick(function() { return _this.pause(); }); } else { return process.nextTick(function() { return _this.poll(title, nQueue + 1); }); } } }); }; Worker.prototype.perform = function(job) { var cb, old_title, _this = this; old_title = process.title; this.emit('job', this, this.queue, job); this.procline("" + this.queue + " job since " + ((new Date).toString())); if (cb = this.callbacks[job["class"]]) { this.workingOn(job); try { return cb.apply(null, __slice.call(job.args).concat([function(result) { try { if (result instanceof Error) { return _this.fail(result, job); } else { return _this.succeed(result, job); } } finally { _this.doneWorking(); process.nextTick((function() { return _this.poll(old_title); })); } }])); } catch (error) { this.fail(new Error(error), job); this.doneWorking(); return process.nextTick((function() { return _this.poll(old_title); })); } } else { this.fail(new Error("Missing Job: " + job["class"]), job); return process.nextTick((function() { return _this.poll(old_title); })); } }; Worker.prototype.succeed = function(result, job) { this.redis.incr(this.conn.key('stat', 'processed')); this.redis.incr(this.conn.key('stat', 'processed', this.name)); return this.emit('success', this, this.queue, job, result); }; Worker.prototype.fail = function(err, job) { this.redis.incr(this.conn.key('stat', 'failed')); this.redis.incr(this.conn.key('stat', 'failed', this.name)); this.redis.rpush(this.conn.key('failed'), JSON.stringify(this.failurePayload(err, job))); return this.emit('error', err, this, this.queue, job); }; Worker.prototype.pause = function() { var _this = this; this.procline("Sleeping for " + (this.conn.timeout / 1000) + "s"); return setTimeout(function() { if (!_this.running) { return; } return _this.poll(); }, this.conn.timeout); }; Worker.prototype.workingOn = function(job) { return this.redis.set(this.conn.key('worker', this.name), JSON.stringify({ run_at: (new Date).toString(), queue: this.queue, payload: job })); }; Worker.prototype.doneWorking = function() { return this.redis.del(this.conn.key('worker', this.name)); }; Worker.prototype.track = function() { this.running = true; return this.redis.sadd(this.conn.key('workers'), this.name); }; Worker.prototype.untrack = function() { return this.redis.srem(this.conn.key('workers'), this.name); }; Worker.prototype.init = function(cb) { var args, _ref; this.track(); args = [this.conn.key('worker', this.name, 'started'), (new Date).toString()]; this.procline("Processing " + this.queues.toString + " since " + args.last); if (cb) { args.push(cb); } return (_ref = this.redis).set.apply(_ref, args); }; Worker.prototype.checkQueues = function() { var _this = this; if (this.queues.shift != null) { return; } if (this.queues === '*') { return this.redis.smembers(this.conn.key('queues'), function(err, resp) { _this.queues = resp ? resp.sort() : []; _this.ready = true; _this.name = _this._name; if (_this.running) { return _this.start(); } }); } else { this.queues = this.queues.split(','); this.ready = true; return this.name = this._name; } }; Worker.prototype.procline = function(msg) { return process.title = "resque-" + exports.version + ": " + msg; }; Worker.prototype.failurePayload = function(err, job) { return { worker: this.name, queue: this.queue, payload: job, exception: err.name, error: err.message, backtrace: err.stack.split('\n').slice(1), failed_at: (new Date).toString() }; }; Object.defineProperty(Worker.prototype, 'name', { get: function() { return this._name; }, set: function(name) { return this._name = this.ready ? [name || 'node', process.pid, this.queues].join(":") : name; } }); return Worker; })(EventEmitter); connectToRedis = function(options) { var redis; redis = require('redis').createClient(options.port, options.host); if (options.password != null) { redis.auth(options.password); } return redis; }; exports.Connection = Connection; exports.Worker = Worker; }).call(this);