Node.js中Bull队列结合cron定时任务生产环境仅触发单个作业问题
根因分析
queue.add是异步方法,你当前在cron的onTick回调中没有等待两个add操作完成,生产环境Redis网络延迟高于本地,极易出现第二个任务还没成功写入Redis,tick事件执行上下文就被销毁,导致任务漏发。- 队列配置已经开启了
removeOnComplete: true,Bull会自动删除执行完成的任务,你在completed事件中额外加了一遍手动删除逻辑,高并发场景下会出现未执行的任务被误删的问题。 - 你代码中
queue.process传入的concurrency变量如果未显式赋值,Bull默认并发数为1,同一时间只能处理1个任务,再加上生产环境的异常逻辑干扰,就会出现两个任务只执行一个的情况。 - 你没有对add操作做异常捕获,无法判断生产环境是否存在第二个任务写入队列时报错的情况。
解决方案
1. 改造cron的onTick逻辑,等待任务全部入队
将onTick改为异步函数,用Promise.all等待两个任务都成功写入Redis再结束回调,同时添加异常捕获:
const cron = new CronJob({ cronTime: '* * * * *', onTick: async function() { workerLogger.info('Pushing test to queue...'); try { await Promise.all([ queue.add('test'), queue.add('healthCheckPing', { jobName: 'test' }) ]); } catch (err) { workerLogger.error('Add job failed: ', err); } }, start: true, timeZone: 'Africa/Lagos', });
2. 移除completed事件中的冗余删除逻辑
删除completed回调中手动删任务的代码,避免误删未执行的任务,修改后回调逻辑如下:
.on('completed', async(job, result) => { workerLogger.info(`Job ID: ${job.id}, Result: ${result}`); })
3. 显式设置合理的并发数
确认concurrency变量的赋值≥2,或者直接显式传入数值:
// 并发数设为2可同时处理2个任务,可根据实际需求调大 queue.process('healthCheckPing', 2, function(job, done) { jobs.healthCheckPing(job.data, done); }); queue.process('test', 2, function(job, done) { jobs.test(job.data, done); });
4. 确认生产环境配置
- 检查Redis连接是否稳定,有没有超时、限流规则拦截写入请求
- 确认CronJob只初始化了一次,避免重复实例化导致的逻辑冲突
- 检查PM2日志,确认没有未捕获的异常导致进程重启、任务丢失
内容的提问来源于stack exchange,提问作者nipek
相关产品推荐
相关产品推荐

