Skip to content

Commit 0376dcc

Browse files
authored
feat(queue): add getCountsPerPriority method (#2746)
1 parent 66ffd9d commit 0376dcc

7 files changed

Lines changed: 125 additions & 35 deletions

File tree

index.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,13 @@ declare namespace Bull {
750750
*/
751751
close(doNotWaitJobs?: boolean): Promise<void>;
752752

753+
/**
754+
* Returns the number of jobs per priority.
755+
*/
756+
getCountsPerPriority(priorities: number[]): Promise<{
757+
[index: string]: number;
758+
}>;
759+
753760
/**
754761
* Returns a promise that will return the job instance associated with the jobId parameter.
755762
* If the specified job cannot be located, the promise callback parameter will be set to null.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--[[
2+
Get counts per provided states
3+
4+
Input:
5+
KEYS[1] wait key
6+
KEYS[2] priority key
7+
8+
ARGV[1...] priorities
9+
]]
10+
local rcall = redis.call
11+
local results = {}
12+
local waitKey = KEYS[1]
13+
local prioritizedKey = KEYS[2]
14+
15+
for i = 1, #ARGV do
16+
local priority = tonumber(ARGV[i])
17+
if priority == 0 then
18+
results[#results+1] = rcall("LLEN", waitKey) - rcall("ZCARD", prioritizedKey)
19+
else
20+
results[#results+1] = rcall("ZCOUNT", prioritizedKey,
21+
priority, priority)
22+
end
23+
end
24+
25+
return results

lib/getters.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,29 @@
22

33
const _ = require('lodash');
44
const Job = require('./job');
5+
const scripts = require('./scripts');
56

67
module.exports = function(Queue) {
78
Queue.prototype.getJob = async function(jobId) {
89
await this.isReady();
910
return Job.fromId(this, jobId);
1011
};
1112

13+
Queue.prototype.getCountsPerPriority = async function(priorities) {
14+
const uniquePriorities = [...new Set(priorities)];
15+
const responses = await scripts.getCountsPerPriority(
16+
this,
17+
uniquePriorities
18+
);
19+
20+
const counts = {};
21+
responses.forEach((res, index) => {
22+
counts[`${uniquePriorities[index]}`] = res || 0;
23+
});
24+
25+
return counts;
26+
};
27+
1228
Queue.prototype._commandByType = function(types, count, callback) {
1329
return _.map(types, type => {
1430
type = type === 'waiting' ? 'wait' : type; // alias

lib/scripts.js

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,21 @@ const scripts = {
8383
return result;
8484
},
8585

86+
getCountsPerPriorityArgs(queue, priorities) {
87+
const keys = [queue.keys.wait, queue.keys.priority];
88+
89+
const args = priorities;
90+
91+
return keys.concat(args);
92+
},
93+
94+
async getCountsPerPriority(queue, priorities) {
95+
const client = await queue.client;
96+
const args = this.getCountsPerPriorityArgs(queue, priorities);
97+
98+
return client.getCountsPerPriority(args);
99+
},
100+
86101
moveToActive(queue, jobId) {
87102
const queueKeys = queue.keys;
88103
const keys = [queueKeys.wait, queueKeys.active, queueKeys.priority];
@@ -253,9 +268,13 @@ const scripts = {
253268
case -2:
254269
return new Error('Missing lock for job ' + jobId + ' ' + command);
255270
case -3:
256-
return new Error(`Job ${jobId} is not in the ${state} state. ${command}`);
271+
return new Error(
272+
`Job ${jobId} is not in the ${state} state. ${command}`
273+
);
257274
case -6:
258-
return new Error(`Lock mismatch for job ${jobId}. Cmd ${command} from ${state}`);
275+
return new Error(
276+
`Lock mismatch for job ${jobId}. Cmd ${command} from ${state}`
277+
);
259278
}
260279
},
261280

test/test_getters.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,29 @@ describe('Jobs getters', function() {
171171
queue.add({ baz: 'qux' });
172172
});
173173

174+
describe('.getCountsPerPriority', () => {
175+
it('returns job counts per priority', done => {
176+
const jobsArray = Array.from(Array(42).keys()).map(index => ({
177+
name: 'test',
178+
data: {},
179+
opts: {
180+
priority: index % 4
181+
}
182+
}));
183+
queue.addBulk(jobsArray).then(() => {
184+
queue.getCountsPerPriority([0, 1, 2, 3]).then(counts => {
185+
expect(counts).to.be.eql({
186+
'0': 11,
187+
'1': 11,
188+
'2': 10,
189+
'3': 10
190+
});
191+
done();
192+
});
193+
});
194+
});
195+
});
196+
174197
it('fails jobs that exceed their specified timeout', done => {
175198
queue.process((job, jobDone) => {
176199
setTimeout(jobDone, 200);

test/test_job.js

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -759,35 +759,35 @@ describe('Job', () => {
759759

760760
it('applies stacktrace limit on failure', () => {
761761
const stackTraceLimit = 1;
762-
return Job.create(queue, { foo: 'bar' }, { stackTraceLimit, attempts: 2 }).then(
763-
job => {
764-
return job
765-
.isFailed()
766-
.then(isFailed => {
767-
expect(isFailed).to.be(false);
768-
})
769-
.then(() => {
770-
return scripts.moveToActive(queue);
771-
})
772-
.then(() => {
773-
return job.moveToFailed(new Error('test error'), true);
774-
})
775-
.then(() => {
776-
return scripts.moveToActive(queue);
777-
})
778-
.then(() => {
779-
return job
780-
.moveToFailed(new Error('test error'), true)
781-
.then(() => {
782-
return job.isFailed().then(isFailed => {
783-
expect(isFailed).to.be(true);
784-
expect(job.stacktrace).not.be(null);
785-
expect(job.stacktrace.length).to.be(stackTraceLimit);
786-
});
787-
});
762+
return Job.create(
763+
queue,
764+
{ foo: 'bar' },
765+
{ stackTraceLimit, attempts: 2 }
766+
).then(job => {
767+
return job
768+
.isFailed()
769+
.then(isFailed => {
770+
expect(isFailed).to.be(false);
771+
})
772+
.then(() => {
773+
return scripts.moveToActive(queue);
774+
})
775+
.then(() => {
776+
return job.moveToFailed(new Error('test error'), true);
777+
})
778+
.then(() => {
779+
return scripts.moveToActive(queue);
780+
})
781+
.then(() => {
782+
return job.moveToFailed(new Error('test error'), true).then(() => {
783+
return job.isFailed().then(isFailed => {
784+
expect(isFailed).to.be(true);
785+
expect(job.stacktrace).not.be(null);
786+
expect(job.stacktrace.length).to.be(stackTraceLimit);
787+
});
788788
});
789-
}
790-
);
789+
});
790+
});
791791
});
792792
});
793793

@@ -914,8 +914,8 @@ describe('Job', () => {
914914
})
915915
.then(state => {
916916
expect(state).to.be('completed');
917-
return client.zrem(queue.toKey('completed'), job.id).then(()=>{
918-
return client.lpush(queue.toKey('active'), job.id)
917+
return client.zrem(queue.toKey('completed'), job.id).then(() => {
918+
return client.lpush(queue.toKey('active'), job.id);
919919
});
920920
})
921921
.then(() => {
@@ -930,8 +930,8 @@ describe('Job', () => {
930930
})
931931
.then(state => {
932932
expect(state).to.be('delayed');
933-
return client.zrem(queue.toKey('delayed'), job.id).then(()=>{
934-
return client.lpush(queue.toKey('active'), job.id)
933+
return client.zrem(queue.toKey('delayed'), job.id).then(() => {
934+
return client.lpush(queue.toKey('active'), job.id);
935935
});
936936
})
937937
.then(() => {

test/test_queue.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1771,7 +1771,7 @@ describe('Queue', () => {
17711771
});
17721772

17731773
queue2
1774-
.add({ foo: 'bar' }, {removeOnFail: true})
1774+
.add({ foo: 'bar' }, { removeOnFail: true })
17751775
.then(job => {
17761776
expect(job.id).to.be.ok;
17771777
expect(job.data.foo).to.be.eql('bar');

0 commit comments

Comments
 (0)