DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

BullMQ 任务一直 waiting:Queue 与 Worker 的 prefix 不一致

Queue和Worker前缀不一致会访问不同命名空间。对照endpoint、db、队列名称和prefix,处理旧任务归属,不盲目重命名Redis键。

Queue 可以成功添加任务,Worker 启动也没有连接错误,任务却始终 waiting。若生产者设置了自定义 prefix,消费者没有设置,应核对它们是否实际指向了两个不同的队列命名空间。

对 Redis 后端,队列名称相同还不够。连接目标、逻辑数据库、队列名称和 BullMQ 前缀都需要一致。默认前缀为 bull;Queue 使用 database、Worker 保留默认值时,两者构造的 Redis 键不同。

对照完整的队列身份

查看生产者、Worker 和 QueueEvents 的实际运行配置,不只比较一份公共配置文件。环境变量或启动包装可能让不同进程获得不同值,也可能让其中一个根本没有接入公共配置。

可以按以下顺序比对:实际 Redis endpoint 与数据库、BullMQ 队列名称,以及传给每个实例的 prefix。日志记录应脱敏,不能输出包含密码的完整连接 URL。

Worker readiness 只表明它准备好工作,不证明它正在监听生产者写入的那个命名空间。先确认需要处理的任务属于哪个完整队列身份,再改消费者。

将同一前缀传给各个参与者

下面是配置关系示例,连接实例应按各自消费者或生产者规则事先建立,processJob 为已有处理函数:

import { Queue, Worker, QueueEvents } from 'bullmq';

const queueName = 'tasks';
const prefix = 'database';

const queue = new Queue(queueName, {
  connection: producerConnection,
  prefix,
});
const worker = new Worker(queueName, processJob, {
  connection: workerConnection,
  prefix,
});
const events = new QueueEvents(queueName, {
  connection: eventsConnection,
  prefix,
});

database 只是前缀示例,不代表 Redis 的逻辑数据库编号。此处使用 BullMQ 的 prefix,不能换成 ioredis 的 keyPrefix:后者与 BullMQ 的键管理不兼容,已有客户端使用它时会遭到相应检查。

如果 Worker 首先报 maxRetriesPerRequest must be null,先处理 已有 ioredis 实例的 Worker 重试设置,再检查命名空间。修好连接选项不会自动把两个前缀合并。

切换前缀不会迁移原来的任务

已经写入 database:tasks 的任务不会因为新 Worker 改成 bull:tasks 就移动过去。变更前保存队列配置与可恢复数据,确认 waiting、active、delayed 等已有任务和重复调度的归属。

只需要修复消费者漏配前缀时,优先让它使用生产者已有的正确命名空间。若确实要迁移命名空间,则需要暂停相应投递、处理活动任务和制定受控迁移方案;不要批量重命名 Redis 键,队列状态、事件、锁与任务之间有关系,改字符串不能保证完整迁移。

也不要删除旧队列来让监控变干净。它可能含尚未完成的任务,前缀回退本身不会撤销已执行的业务。

验收时选取一项已知、可安全处理的任务,核对它从正确命名空间的 waiting 进入 active,再按实际业务进入 completed 或 failed。观察事件也使用同一前缀,排除另一个正常队列掩盖原来的积压。