问题
I am using bull queue to process some jobs. In the current scenario each job is some kind of an operation. So whenever an operation(job) among a list of operations in the queue fails, queue has to stop processing the remaining jobs(operations).
What have I tried so far?
So i tried to pause the queue when a particular job fails. Next the queue is resumed when it drains. Now when it is resumed the queue does not start from the failed job instead picks up the next job.
var Queue = require('bull');
let redisOptions = {
redis: { port: 6379, host: '127.0.0.1' },
limiter: { max: 1, duration: 1000 }
}
var myQueue = new Queue('Linear-Queue', redisOptions);
myQueue.process('Type-1', function (job, done) {
setTimeout(() => {
done(job.data.error);
}, job.data.time);
});
let options = {
attempts: 3,
removeOnComplete: false, // removes job from queue on success
removeOnFail: false // removes job from queue on failure
}
setTimeout(() => {
myQueue.add('Type-1', { time: 10000, description: "Type-1 One", error: false }, options);
}, 1 * 1000);
setTimeout(() => {
myQueue.add('Type-1', { time: 5000, description: "Type-1 two", error: true }, options);
}, 2 * 1000);
setTimeout(() => {
myQueue.add('Type-1', { time: 3000, description: "Type-1 three", error: false }, options);
}, 3 * 1000);
myQueue.on('completed', function (job, result) {
console.log("Completed: " + job.data.description);
});
myQueue.on('failed', async function (job, error) {
console.log("Failed: " + job.data.description);
try {
await myQueue.pause();
} catch (error) {
console.log(error);
}
});
myQueue.on('drained', async function () {
try {
await myQueue.resume();
} catch (error) {
console.log(error);
}
});
Current Output:
Expected Output: if the Type-1 two
completes successfully in 3rd attempt.
Completed: Type-1 One
Failed: Type-1 two
Failed: Type-1 two
Completed: Type-1 two
Completed: Type-1 three
Expected Output: if the Type-1 two
failed in 3rd attempt as well.
Completed: Type-1 One
Failed: Type-1 two
Failed: Type-1 two
Failed: Type-1 two
All i want is the queue has to stop processing new jobs until current job is completed without any failure. In case of any failure, the failed job has to run some x
number of time. At the x+1
attempt it has to clear(delete all jobs) the queue. So how to achieve this linear behavior in queue.
回答1:
var Queue = require('bull');
let redisOptions = {
redis: {
port: 6379,
host: '127.0.0.1'
},
// Maximum one job is processed every 5 seconds.
limiter: {
max: 1,
duration: 5000
},
settings: {
backoffStrategies: {
// Custom backoff strategy.
myStrategy: function (attemptsMade, error) {
return error.delay || 60 * 1000;
}
}
}
};
var myQueue = new Queue('Linear-Queue', redisOptions);
myQueue.process('Type-1', function (job, done) {
setTimeout(() => {
// compare attemptsMade with 3, to test 'on-all-attempts-fail' scenario.
if (job.attemptsMade == 2) {
done(false);
} else {
done(job.data.error);
}
}, job.data.time);
});
let options = {
attempts: 3,
backoff: {
type: 'myStrategy'
},
removeOnComplete: false, // Set to true if job has to be removed on success.
removeOnFail: false // Set to true if job has to be removed on failure.
}
for (let i = 1; i <= 10; i++) {
let error = false;
if (i == 2) {
error = true
}
myQueue.add('Type-1', { time: i * 1000, description: "Type-1 Job-" + i, error: error }, options);
// You can also add job with some time gap.
// setTimeout(i => {
// myQueue.add('Type-1', { time: i * 1000, description: "Type-1 Job-" + i, error: error }, options);
// }, 1000, i);
}
myQueue.on('completed', async function (job, result) {
console.log("Completed: Job " + job.id);
});
myQueue.on('failed', async function (job, error) {
console.log("Failed: Job " + job.id + " on attempt " + job.attemptsMade);
handelFailure(job);
});
myQueue.on('error', function (error) {
console.log("Queue: on error");
console.log(error);
});
async function handelFailure(currentJob) {
if (currentJob.opts.attempts == currentJob.attemptsMade) {
// Remove all jobs in queue and clan the redis.
await myQueue.clean(70 * 1000, 'wait');
await myQueue.clean(70 * 1000, 'active');
await myQueue.clean(70 * 1000, 'failed');
await myQueue.clean(70 * 1000, 'paused');
await myQueue.clean(70 * 1000, 'delayed');
await myQueue.empty();
return;
}
let pendingJobs = await myQueue.getJobs(['waiting', 'active', 'failed', 'paused', 'delayed'], 0, -1, true);
console.log("Failing all remaining " + pendingJobs.length + " jobs...");
for (let i = 0; i < pendingJobs.length; i++) {
let currentJobId = parseInt(currentJob.id);
let pendingJobId = parseInt(pendingJobs[i].id);
if (pendingJobId <= currentJobId) {
continue;
}
let errorInfo = {
delay: (70 * 1000) + (i * 5 * 1000),
message: "Moving " + pendingJobId + " to failed queue."
}
await pendingJobs[i].moveToFailed(errorInfo, true);
}
}
Output 1: When job 2 completed successfully on 3rd attempt.
Output 2: When job 2 failed in all its 3 attempts (queue stops processing remaining jobs as expected).
来源:https://stackoverflow.com/questions/61659677/bull-queue-when-a-job-fails-how-to-stop-queue-from-processing-remaining-jobs