Bull queue: When a job fails, how to stop queue from processing remaining jobs?

南笙酒味 提交于 2020-05-14 12:53:41

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!