You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
274 lines
7.3 KiB
274 lines
7.3 KiB
1 month ago
|
'use strict';
|
||
|
|
||
|
const _ = require('lodash');
|
||
|
const Job = require('./job');
|
||
|
const scripts = require('./scripts');
|
||
|
|
||
|
module.exports = function(Queue) {
|
||
|
Queue.prototype.getJob = async function(jobId) {
|
||
|
await this.isReady();
|
||
|
return Job.fromId(this, jobId);
|
||
|
};
|
||
|
|
||
|
Queue.prototype.getCountsPerPriority = async function(priorities) {
|
||
|
const uniquePriorities = [...new Set(priorities)];
|
||
|
const responses = await scripts.getCountsPerPriority(
|
||
|
this,
|
||
|
uniquePriorities
|
||
|
);
|
||
|
|
||
|
const counts = {};
|
||
|
responses.forEach((res, index) => {
|
||
|
counts[`${uniquePriorities[index]}`] = res || 0;
|
||
|
});
|
||
|
|
||
|
return counts;
|
||
|
};
|
||
|
|
||
|
Queue.prototype._commandByType = function(types, count, callback) {
|
||
|
return _.map(types, type => {
|
||
|
type = type === 'waiting' ? 'wait' : type; // alias
|
||
|
|
||
|
const key = this.toKey(type);
|
||
|
|
||
|
switch (type) {
|
||
|
case 'completed':
|
||
|
case 'failed':
|
||
|
case 'delayed':
|
||
|
case 'repeat':
|
||
|
return callback(key, count ? 'zcard' : 'zrange');
|
||
|
case 'active':
|
||
|
case 'wait':
|
||
|
case 'paused':
|
||
|
return callback(key, count ? 'llen' : 'lrange');
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
Returns the number of jobs waiting to be processed.
|
||
|
*/
|
||
|
Queue.prototype.count = function() {
|
||
|
return this.getJobCountByTypes('wait', 'paused', 'delayed');
|
||
|
};
|
||
|
|
||
|
// Job counts by type
|
||
|
// Queue#getJobCountByTypes('completed') => completed count
|
||
|
// Queue#getJobCountByTypes('completed,failed') => completed + failed count
|
||
|
// Queue#getJobCountByTypes('completed', 'failed') => completed + failed count
|
||
|
// Queue#getJobCountByTypes('completed,waiting', 'failed') => completed + waiting + failed count
|
||
|
Queue.prototype.getJobCountByTypes = function() {
|
||
|
return this.getJobCounts.apply(this, arguments).then(result => {
|
||
|
return _.chain(result)
|
||
|
.values()
|
||
|
.sum()
|
||
|
.value();
|
||
|
});
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Returns the job counts for each type specified or every list/set in the queue by default.
|
||
|
*
|
||
|
*/
|
||
|
Queue.prototype.getJobCounts = function() {
|
||
|
const types = parseTypeArg(arguments);
|
||
|
const multi = this.multi();
|
||
|
|
||
|
this._commandByType(types, true, (key, command) => {
|
||
|
multi[command](key);
|
||
|
});
|
||
|
|
||
|
return multi.exec().then(res => {
|
||
|
const counts = {};
|
||
|
res.forEach((res, index) => {
|
||
|
counts[types[index]] = res[1] || 0;
|
||
|
});
|
||
|
return counts;
|
||
|
});
|
||
|
};
|
||
|
|
||
|
Queue.prototype.getCompletedCount = function() {
|
||
|
return this.getJobCountByTypes('completed');
|
||
|
};
|
||
|
|
||
|
Queue.prototype.getFailedCount = function() {
|
||
|
return this.getJobCountByTypes('failed');
|
||
|
};
|
||
|
|
||
|
Queue.prototype.getDelayedCount = function() {
|
||
|
return this.getJobCountByTypes('delayed');
|
||
|
};
|
||
|
|
||
|
Queue.prototype.getActiveCount = function() {
|
||
|
return this.getJobCountByTypes('active');
|
||
|
};
|
||
|
|
||
|
Queue.prototype.getWaitingCount = function() {
|
||
|
return this.getJobCountByTypes('wait', 'paused');
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* @returns the potential stalled jobs. Only useful for tests.
|
||
|
*/
|
||
|
Queue.prototype.getStalledCount = function() {
|
||
|
const key = this.toKey('stalled');
|
||
|
return this.client.scard(key);
|
||
|
};
|
||
|
|
||
|
// TO BE DEPRECATED --->
|
||
|
Queue.prototype.getPausedCount = function() {
|
||
|
return this.getJobCountByTypes('paused');
|
||
|
};
|
||
|
// <-----
|
||
|
|
||
|
Queue.prototype.getWaiting = function(start, end, opts) {
|
||
|
return this.getJobs(['wait', 'paused'], start, end, true, opts);
|
||
|
};
|
||
|
|
||
|
Queue.prototype.getActive = function(start, end, opts) {
|
||
|
return this.getJobs('active', start, end, true, opts);
|
||
|
};
|
||
|
|
||
|
Queue.prototype.getDelayed = function(start, end, opts) {
|
||
|
return this.getJobs('delayed', start, end, true, opts);
|
||
|
};
|
||
|
|
||
|
Queue.prototype.getCompleted = function(start, end, opts) {
|
||
|
return this.getJobs('completed', start, end, false, opts);
|
||
|
};
|
||
|
|
||
|
Queue.prototype.getFailed = function(start, end, opts) {
|
||
|
return this.getJobs('failed', start, end, false, opts);
|
||
|
};
|
||
|
|
||
|
Queue.prototype.getRanges = function(types, start, end, asc) {
|
||
|
start = _.isUndefined(start) ? 0 : start;
|
||
|
end = _.isUndefined(end) ? -1 : end;
|
||
|
|
||
|
const multi = this.multi();
|
||
|
const multiCommands = [];
|
||
|
|
||
|
this._commandByType(parseTypeArg(types), false, (key, command) => {
|
||
|
switch (command) {
|
||
|
case 'lrange':
|
||
|
if (asc) {
|
||
|
multiCommands.push('lrange');
|
||
|
multi.lrange(key, -(end + 1), -(start + 1));
|
||
|
} else {
|
||
|
multi.lrange(key, start, end);
|
||
|
}
|
||
|
break;
|
||
|
case 'zrange':
|
||
|
multiCommands.push('zrange');
|
||
|
if (asc) {
|
||
|
multi.zrange(key, start, end);
|
||
|
} else {
|
||
|
multi.zrevrange(key, start, end);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
return multi.exec().then(responses => {
|
||
|
let results = [];
|
||
|
|
||
|
responses.forEach((response, index) => {
|
||
|
const result = response[1] || [];
|
||
|
|
||
|
if (asc && multiCommands[index] === 'lrange') {
|
||
|
results = results.concat(result.reverse());
|
||
|
} else {
|
||
|
results = results.concat(result);
|
||
|
}
|
||
|
});
|
||
|
return results;
|
||
|
});
|
||
|
};
|
||
|
|
||
|
Queue.prototype.getJobs = function(types, start, end, asc, opts) {
|
||
|
return this.getRanges(types, start, end, asc).then(jobIds => {
|
||
|
return Promise.all(jobIds.map(jobId => this.getJobFromId(jobId, opts)));
|
||
|
});
|
||
|
};
|
||
|
|
||
|
Queue.prototype.getJobLogs = function(jobId, start, end, asc = true) {
|
||
|
start = _.isUndefined(start) ? 0 : start;
|
||
|
end = _.isUndefined(end) ? -1 : end;
|
||
|
|
||
|
const multi = this.multi();
|
||
|
|
||
|
const logsKey = this.toKey(jobId + ':logs');
|
||
|
if (asc) {
|
||
|
multi.lrange(logsKey, start, end);
|
||
|
} else {
|
||
|
multi.lrange(logsKey, -(end + 1), -(start + 1));
|
||
|
}
|
||
|
multi.llen(logsKey);
|
||
|
return multi.exec().then(result => {
|
||
|
if (!asc) {
|
||
|
result[0][1].reverse();
|
||
|
}
|
||
|
return {
|
||
|
logs: result[0][1],
|
||
|
count: result[1][1]
|
||
|
};
|
||
|
});
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Get queue metrics related to the queue.
|
||
|
*
|
||
|
* This method returns the gathered metrics for the queue.
|
||
|
* The metrics are represented as an array of job counts
|
||
|
* per unit of time (1 minute).
|
||
|
*
|
||
|
* @param start - Start point of the metrics, where 0
|
||
|
* is the newest point to be returned.
|
||
|
* @param end - End poinf of the metrics, where -1 is the
|
||
|
* oldest point to be returned.
|
||
|
*
|
||
|
* @returns - Returns an object with queue metrics.
|
||
|
*/
|
||
|
Queue.prototype.getMetrics = async function(type, start = 0, end = -1) {
|
||
|
const metricsKey = this.toKey(`metrics:${type}`);
|
||
|
const dataKey = `${metricsKey}:data`;
|
||
|
|
||
|
const multi = this.multi();
|
||
|
multi.hmget(metricsKey, 'count', 'prevTS', 'prevCount');
|
||
|
multi.lrange(dataKey, start, end);
|
||
|
multi.llen(dataKey);
|
||
|
|
||
|
const [hmget, range, len] = await multi.exec();
|
||
|
const [err, [count, prevTS, prevCount]] = hmget;
|
||
|
const [err2, data] = range;
|
||
|
const [err3, numPoints] = len;
|
||
|
if (err || err2) {
|
||
|
throw err || err2 || err3;
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
meta: {
|
||
|
count: parseInt(count || '0', 10),
|
||
|
prevTS: parseInt(prevTS || '0', 10),
|
||
|
prevCount: parseInt(prevCount || '0', 10)
|
||
|
},
|
||
|
data,
|
||
|
count: numPoints
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
function parseTypeArg(args) {
|
||
|
const types = _.chain([])
|
||
|
.concat(args)
|
||
|
.join(',')
|
||
|
.split(/\s*,\s*/g)
|
||
|
.compact()
|
||
|
.value();
|
||
|
|
||
|
return types.length
|
||
|
? types
|
||
|
: ['waiting', 'active', 'completed', 'failed', 'delayed', 'paused'];
|
||
|
}
|