mikser
Version:
Real-time static site generator
135 lines (118 loc) • 3.75 kB
JavaScript
var Promise = require('bluebird');
var moment = require('moment');
var S = require('string');
var _ = require('lodash');
module.exports = function(mikser) {
mikser.queue = {
concurrency: mikser.config.workers * 3,
processed: 0,
pending: 0,
remainingTime: 0,
averageTime: 0
};
let debug = mikser.debug('queue');
let started = false;
let concurent = 0;
let queue = [];
let startTime = new Date().getTime();
function dequeue() {
debug('Concurent:', concurent, 'Left:', queue.length);
if (!queue.length) return;
while(concurent < mikser.queue.concurrency && queue.length) {
concurent++;
let action = queue.shift().action;
if (_.isFunction(action)) action = action();
Promise.resolve(action).finally(() => {
mikser.queue.processed++;
concurent--;
mikser.queue.pending = queue.length + concurent;
if (mikser.queue.processed > mikser.queue.concurrency * 3) {
let currentTime = new Date().getTime();
mikser.queue.averageTime = Math.round((currentTime - startTime) / mikser.queue.processed);
mikser.queue.remainingTime = mikser.queue.averageTime * mikser.queue.pending;
debug('Elapsed time:', currentTime - startTime, 'Average time:', mikser.queue.averageTime, 'Remaining time:', mikser.queue.remainingTime);
}
let status = 'Processed: ' + mikser.queue.processed;
if (mikser.queue.pending) {
status += ' Pending: ' + mikser.queue.pending;
}
if (mikser.queue.averageTime && mikser.queue.pending > mikser.queue.concurrency) {
let duration = moment.duration(mikser.queue.remainingTime);
status += ' Remaining time: ' +
S(duration.hours()).padLeft(2, '0') + ':' +
S(duration.minutes()).padLeft(2, '0') + ':' +
S(duration.seconds()).padLeft(2, '0');
}
if (mikser.options.debug) {
debug(status);
} else if (!mikser.queue.pending) {
mikser.diagnostics.log(status);
} else {
mikser.diagnostics.progress(status);
}
dequeue();
});
}
}
mikser.queue.start = function() {
if (!queue.length) return Promise.resolve();
if (started) return started;
mikser.queue.processed = 0;
mikser.queue.pending = queue.length;
mikser.queue.remainingTime = 0;
mikser.queue.averageTime = 0;
started = new Promise((resolve, reject) => {
startTime = new Date().getTime();
dequeue();
let interval = setInterval(() => {
if (!mikser.queue.pending) {
clearInterval(interval);
let endTime = new Date().getTime();
let duration = moment.duration(endTime - startTime);
mikser.diagnostics.log('info','Generation time:',
S(duration.hours()).padLeft(2, '0') + ':' +
S(duration.minutes()).padLeft(2, '0') + ':' +
S(duration.seconds()).padLeft(2, '0'));
resolve();
started = false;
}
}, 1000);
});
return started;
}
mikser.queue.drain = function() {
debug('Draining queue');
queue = [];
mikser.queue.pending = 0;
}
mikser.queue.clean = function() {
if (started) return;
debug('Clening queue');
queue = _.filter(queue, (action) => {
if (action instanceof Promise) {
return action.isPending();
}
return true;
});
}
mikser.queue.push = function(documentId, action) {
queue.push({
action: action,
documentId: documentId
});
}
mikser.queue.unshift = function(documentId, action) {
queue.unshift({
action: action,
documentId: documentId
});
}
mikser.queue.isPending = function(documentId) {
for(let item of queue) {
if(item.documentId == documentId) return true;
}
return false;
}
return Promise.resolve(mikser);
}