Files
asciidisco.com/build/node_modules/fqueue/fqueue.js
2023-08-01 13:49:46 +02:00

169 lines
3.7 KiB
JavaScript

module.exports = FunctionQueue;
var util = require('util'),
EventEmitter = require('events').EventEmitter;
var debug = false;
function JobQueueReattempt(max, timeout) {
this.max = isNaN(max) ? 3 : max;
this.timeout = isNaN(timeout) ? 0 : timeout;
this.attempts = 0;
}
function FunctionQueue(options) {
if(!(this instanceof FunctionQueue)) return new FunctionQueue(options);
var self = this;
this.scope = this;
this.maxPending = -1;
this.maxAttempts = 3;
this.attemptTimeout = 5000;
options = options || {};
Object.keys(options).forEach(function(k) {
if(self.hasOwnProperty(k)) {
self[k] = options[k];
}
});
this._reset();
}
util.inherits(FunctionQueue, EventEmitter);
FunctionQueue.prototype._reset = function() {
this.running = false;
this.paused = false;
this.pending = 0;
this.dequeued = 0;
this.warnings = 0;
this.errors = 0;
this.attempts = 0;
this.queue = [];
return this;
};
FunctionQueue.prototype.isEmpty = function() {
if(this.queue.length) {
return false;
} else {
return true;
}
};
FunctionQueue.prototype.error = function(err, func, args, scope, maxAttempts, timeout) {
debug&&console.log('error', func);
var r;
if(args[args.length-1] instanceof JobQueueReattempt) {
r = args[args.length-1];
r.attempts += 1;
} else {
this.warnings += 1;
r = new JobQueueReattempt(
maxAttempts != null ? maxAttempts : this.maxAttempts,
timeout != null ? timeout : this.attemptTimeout
);
args = Array.prototype.slice.call(args, 0);
args.push(r);
}
if(r.attempts === r.max) {
this.warnings -= 1;
this.errors += 1;
this.emit('error', err);
} else {
this.attempts += 1;
this.emit('retry', func, args, err, r, scope);
this.enqueue(func, args, scope, r.timeout);
}
return this;
};
FunctionQueue.prototype.start = function(func, args, scope, timeout) {
if(this.running) {
throw new Error('Can not start a running FunctionQueue.');
}
this._reset();
this.running = true;
this.enqueue(func, args, scope, timeout);
this._dequeue();
return this;
};
FunctionQueue.prototype.enqueue = function(func, args, scope, timeout) {
debug&&console.log('enqueue', func);
if(timeout) {
this.queue.push([this._timeout, this, [timeout, func, scope, args]]);
} else {
if(typeof func === 'string') { func = (scope||this.scope)[func]; }
this.queue.push([func, scope||this.scope, args]);
}
return this;
};
FunctionQueue.prototype._timeout = function(timeout, func, scope, args) {
debug&&console.log('_timeout', timeout, func);
var self = this;
setTimeout(function() {
self.enqueue(func, args, scope);
self.done();
}, timeout);
};
FunctionQueue.prototype._dequeue = function() {
debug&&console.log('_dequeue');
if(this.paused) {
return;
}
while(this.maxPending <= 0 || this.pending < this.maxPending) {
var item = this.queue.shift();
if(item) {
this.pending += 1;
this.dequeued += 1;
item[0].apply(item[1], item[2]);
} else {
break;
}
}
};
FunctionQueue.prototype.done = function() {
debug&&console.log('done');
this.pending -= 1;
if(this.isEmpty() === false && (this.maxPending <= 0 || this.pending < this.maxPending)) {
this._dequeue();
}
if(this.pending === 0) {
if(this.paused) {
this.emit('pause');
} else {
this.running = false;
this.emit('done');
}
}
return this;
};
FunctionQueue.prototype.pause = function() {
this.paused = true;
return this;
};
FunctionQueue.prototype.resume = function() {
if(this.paused) {
this.paused = false;
if(this.isEmpty()) {
this.pending = 1;
this.done();
} else {
this._dequeue();
this.emit('resume');
}
}
return this;
};