Bull队列:如何标记任务为失败并实现手动重试?
问题
我司采用Bull队列系统接收API请求,待每个请求完成后依次转发至ERP系统(避免用户批量发起请求导致ERP崩溃)。当前ERP处理API命令失败时,任务会被标记为Bull队列的「已完成」状态,仅自定义失败标识。
现需实现:
- 当ERP处理失败时,将对应任务标记为Bull的「失败」状态,且不影响其他任务执行;
- 支持手动重试失败任务(需用户手动调整后重试,而非自动重试)。
查看Bull文档得知done回调可传入Error实例标记任务失败,但无示例。现有处理代码如下:
queue.process(async (job, done) => { switch (job.data.type) { case 'API_Type': const workOrder = await createWorkOrder(job.data) socketService.emiter('API_Type', workOrder, job.data.socketId) workOrder.status === 'success' ? done(null, workOrder) : placeJobInFailedStatus break //... default: done() } })
请问如何替换代码中的placeJobInFailedStatus以标记任务为失败状态?另外,Bull是否原生支持手动重试失败任务?文档中的job.retry和job.promote如何调用?是否需自行实现重试逻辑?
解决方案
一、替换placeJobInFailedStatus标记任务失败
直接调用done回调并传入Error实例即可,Bull会自动将该任务标记为失败状态,且不会影响其他任务执行(Bull的任务是独立隔离处理的)。
修改后的代码片段如下:
queue.process(async (job, done) => { switch (job.data.type) { case 'API_Type': const workOrder = await createWorkOrder(job.data) socketService.emiter('API_Type', workOrder, job.data.socketId) if (workOrder.status === 'success') { done(null, workOrder) } else { // 传入Error实例,可携带ERP返回的失败详情 done(new Error(`ERP处理失败: ${workOrder.errorMsg || '未知错误'}`)) } break //... default: done() } })
这里用if-else替代三元表达式可读性更强,Error消息可以根据实际场景传入具体失败信息,方便后续排查问题。
二、Bull原生支持手动重试失败任务,无需自行实现核心逻辑
Bull提供了现成API处理失败任务的手动重试,具体用法如下:
获取失败任务
先从队列中查询失败任务列表,或根据任务ID直接获取单个任务:// 获取所有失败任务,可添加过滤条件(如按类型、时间范围) const failedJobs = await queue.getFailed() // 根据任务ID获取单个失败任务 const failedJob = await queue.getJob('任务ID')调用
job.retry()发起重试
获取到失败任务后,直接调用retry()即可将任务重新放回待处理队列。如果需要在重试前修改任务数据(比如用户调整了参数),可以先更新数据再重试:// 示例:修改任务参数后重试 failedJob.data = { ...failedJob.data, targetParam: '新参数值' } await failedJob.save() // 发起重试 await failedJob.retry()job.promote()的作用promote()主要用于将被延迟(delayed)的任务提前加入待处理队列,一般手动重试失败任务时不需要调用。只有当重试后的任务处于延迟状态时,才需要用它立即触发处理。
内容的提问来源于stack exchange,提问作者Ben in CA

