bullmq vs bull vs agenda vs bee-queue vs kue vs node-resque
Node.js 任务队列库选型指南
bullmqbullagendabee-queuekuenode-resque类似的npm包:
Node.js 任务队列库选型指南

agendabee-queuebullbullmqkuenode-resque 都是 Node.js 生态中用于处理异步任务队列的流行库。它们允许开发者将耗时操作(如发送邮件、处理文件、调用外部 API)从主请求流程中解耦,放入后台队列异步执行,从而提升 Web 应用的响应速度和可靠性。这些库通常依赖 Redis 或 MongoDB 作为底层存储,提供任务调度、失败重试、延迟执行、并发控制等核心功能,是构建高可用后端服务的关键组件。

npm下载趋势
3 年
GitHub Stars 排名
统计详情
npm包名称
下载量
Stars
大小
Issues
发布时间
License
bullmq2,982,0598,4172.29 MB33615 小时前MIT
bull1,276,25116,233309 kB1461 年前MIT
agenda156,6719,623295 kB212 小时前MIT
bee-queue29,3134,018107 kB382 个月前MIT
kue22,5379,465-2889 年前MIT
node-resque19,3551,409708 kB148 天前Apache-2.0

Node.js 任务队列库深度对比:Agenda、Bee-Queue、Bull、BullMQ、Kue 与 node-resque

在构建现代 Web 应用时,我们常常需要将耗时操作(如发送邮件、生成报表、处理上传文件)从主请求流程中剥离出来,交给后台任务队列异步处理。Node.js 生态中有多个成熟的任务队列库,它们都基于 Redis 或 MongoDB 等存储后端,但在 API 设计、功能特性、维护状态和适用场景上存在显著差异。本文将从实际工程角度出发,深入比较 Agenda、Bee-Queue、Bull、BullMQ、Kue 和 node-resque,帮助你做出明智的技术选型。

⚠️ 首要提醒:部分库已不再维护

在深入技术细节前,必须明确一点:Kue 已被官方标记为废弃(deprecated)。其 GitHub 仓库 README 明确写道:“Kue is no longer maintained. We recommend using Bull instead.” 因此,任何新项目都不应再选用 Kue。同样,虽然 node-resque 仍在更新,但其社区活跃度和文档完整性远不如 Bull 系列,需谨慎评估。

🗄️ 存储后端:Redis 还是 MongoDB?

任务队列库的底层存储直接影响部署架构和运维复杂度。

  • Agenda 是唯一使用 MongoDB 的主流选项。如果你的应用已经重度依赖 MongoDB 且希望避免引入 Redis,Agenda 是自然选择。
// Agenda: 使用 MongoDB
const agenda = new Agenda({ db: { address: 'mongodb://127.0.0.1:27017/agenda' } });
agenda.define('send email', async (job) => {
  await sendEmail(job.attrs.data.to);
});
  • Bee-Queue、Bull、BullMQ、Kue、node-resque 均基于 Redis。Redis 的高性能和原子操作使其成为任务队列的理想存储。
// Bull: 使用 Redis
const queue = new Queue('send email', { redis: { port: 6379, host: '127.0.0.1' } });
queue.process('send email', async (job) => {
  await sendEmail(job.data.to);
});

// BullMQ: 使用 Redis(新版 API)
const worker = new Worker('send email', async (job) => {
  await sendEmail(job.data.to);
}, { connection: { host: '127.0.0.1', port: 6379 } });

// Bee-Queue: 使用 Redis
const queue = new Queue('send email', { redis: { host: '127.0.0.1', port: 6379 } });
queue.process(async (job) => {
  await sendEmail(job.data.to);
});

// node-resque: 使用 Redis
const queue = new Queue({ connection: { host: '127.0.0.1', port: 6379 } });
queue.enqueue('send email', 'sendEmail', [to]);

💡 建议:除非已有 MongoDB 技术栈,否则优先选择 Redis 方案 —— 它更轻量、更快,且专为这类场景优化。

🔧 API 设计哲学:面向对象 vs 函数式 vs 声明式

不同库对“如何定义和处理任务”有截然不同的抽象方式。

Agenda:面向 Job 实例

Agenda 将任务视为可调度的对象,支持复杂的重复计划(类似 cron)。

// Agenda: 定义任务并立即或定时执行
agenda.define('delete old users', async (job) => {
  await User.remove({ lastLoginAt: { $lt: twoDaysAgo } });
});

// 每天凌晨 2 点运行
await agenda.every('2 hours', 'delete old users');
// 或立即运行一次
await agenda.now('delete old users');

Bull / BullMQ:声明式队列与处理器分离

Bull 系列强调“队列”作为核心实体,任务(Job)通过名称提交,由独立的处理器消费。

// Bull: 提交任务
const job = await queue.add('send email', { to: 'user@example.com' });

// BullMQ: 更清晰的分离
const job = await queue.add('send email', { to: 'user@example.com' });
// 处理器在另一处定义(可能在不同进程)
const worker = new Worker('send email', async (job) => { /* ... */ });

Bee-Queue:简洁的链式 API

Bee-Queue 采用更函数式的风格,任务处理逻辑直接绑定到队列实例。

// Bee-Queue: 定义处理逻辑并提交任务
const emailQueue = new Queue('email');
emailQueue.process(async (job) => {
  return sendEmail(job.data.to);
});

// 提交任务
const job = await emailQueue.createJob({ to: 'user@example.com' }).save();

node-resque:仿 Ruby Resque 的命令式风格

node-resque 的 API 较为底层,需手动管理队列、任务注册和工作进程。

// node-resque: 注册任务函数
const jobs = {
  sendEmail: {
    perform: async (to) => await sendEmail(to)
  }
};

// 提交任务
await queue.enqueue('default', 'sendEmail', ['user@example.com']);

// 启动工作进程
const worker = new Worker({ connection: {}, queues: ['default'] }, jobs);
worker.start();

💡 建议:BullMQ 的 API 最符合现代工程实践 —— 清晰分离生产者与消费者,类型安全更好,适合大型项目。

⏱️ 任务调度与重试机制

可靠的任务队列必须处理失败重试和延迟执行。

延迟任务(Delayed Jobs)

// Agenda: 内置延迟支持
await agenda.schedule('in 10 minutes', 'send email', { to: 'user@example.com' });

// Bull: 通过 delay 选项
await queue.add('send email', { to: 'user@example.com' }, { delay: 10 * 60 * 1000 });

// BullMQ: 同 Bull
await queue.add('send email', { to: 'user@example.com' }, { delay: 600000 });

// Bee-Queue: 通过 delay() 方法
await emailQueue.createJob({ to: 'user@example.com' }).delay(600000).save();

// node-resque: 不直接支持延迟任务,需自行实现

重试策略(Retry Strategies)

// Bull: 内置重试,支持 backoff
await queue.add('send email', data, {
  attempts: 3,
  backoff: { type: 'exponential', delay: 1000 }
});

// BullMQ: 更强大的重试配置
await queue.add('send email', data, {
  attempts: 5,
  backoff: { type: 'custom', delay: (attemptsMade) => Math.pow(2, attemptsMade) * 1000 }
});

// Bee-Queue: 通过 retries 选项
await emailQueue.createJob(data).retries(3).save();

// Agenda: 通过 fail event 手动重试
agenda.on('fail', async (err, job) => {
  if (job.attrs.failures < 3) {
    await job.repeatEvery('5 minutes').save();
  }
});

💡 建议:BullMQ 提供最灵活的重试和退避策略,适合对可靠性要求高的场景。

📊 监控与可观测性

生产环境必须能监控队列状态、任务积压和失败率。

  • Bull / BullMQ 提供内置的 Web UI(通过 bull-board@bull-board/ui),可实时查看队列、任务状态、重试情况。
  • Agenda 无官方 UI,但可通过查询 MongoDB 监控任务。
  • Bee-Queuenode-resque 需自行实现监控逻辑,或依赖 Redis 监控工具。
// BullMQ + bull-board 示例
import { createBullBoard } from '@bull-board/api';
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter';
import { ExpressAdapter } from '@bull-board/express';

const serverAdapter = new ExpressAdapter();
createBullBoard({
  queues: [new BullMQAdapter(myQueue)],
  serverAdapter
});
app.use('/admin/queues', serverAdapter.getRouter());

💡 建议:若需开箱即用的监控能力,BullMQ 是最佳选择。

🔄 迁移路径与未来演进

  • BullMQ 是 Bull 的现代化继任者,使用 TypeScript 重写,修复了 Bull 的许多设计缺陷(如内存泄漏、类型不安全)。官方推荐新项目直接使用 BullMQ。
  • Agenda 仍在维护,但更新较慢,适合 MongoDB 技术栈项目。
  • Bee-Queue 轻量简洁,适合小型项目或对依赖大小敏感的场景。
  • node-resque 适合已有 Ruby Resque 经验的团队,但学习曲线较陡。
  • Kue 已废弃,切勿用于新项目

📌 总结:如何选择?

场景推荐库理由
全新项目,追求现代化、类型安全、强大功能BullMQ完整的 TypeScript 支持、灵活的重试/延迟、优秀监控生态
已有 MongoDB 技术栈,不想引入 RedisAgenda唯一成熟的 MongoDB 任务队列方案
轻量级需求,简单任务处理,小团队快速迭代Bee-QueueAPI 简洁,代码量少,易于理解
从 Ruby Resque 迁移,或熟悉其模型node-resque概念一致,但需接受较弱的文档和生态
任何新项目避免 Kue官方已废弃,存在未修复 bug 和安全风险

最终,任务队列库的选择应基于你的技术栈现状、团队熟悉度和长期维护成本。对于绝大多数新项目,BullMQ 是最平衡、最面向未来的选择

如何选择: bullmq vs bull vs agenda vs bee-queue vs kue vs node-resque
  • bullmq:

    选择 bullmq 作为新项目的首选。它是 Bull 的现代化重写,采用 TypeScript 开发,提供更强的类型安全、更灵活的重试/延迟配置、更低的内存占用和更好的监控集成。API 设计清晰,分离了生产者与消费者,适合中大型应用的长期维护。

  • bull:

    选择 bull 如果你正在维护一个已使用它的老项目,或者需要一个成熟稳定的 Redis 队列方案。它拥有丰富的功能和活跃的社区插件(如 bull-board)。但新项目应优先考虑其继任者 BullMQ,因为 Bull 存在一些已知的设计缺陷和内存问题。

  • agenda:

    选择 agenda 如果你的项目已经重度使用 MongoDB 且希望避免引入 Redis 依赖。它提供了类似 cron 的复杂调度能力,适合需要基于时间触发的周期性任务场景。但需注意其 API 较为老旧,且缺乏官方 Web UI 监控工具。

  • bee-queue:

    选择 bee-queue 如果你需要一个轻量、简洁、无额外依赖(仅需 Redis)的任务队列方案。它的 API 设计直观,适合小型项目或对 bundle size 敏感的场景。但功能相对基础,缺少高级重试策略和内置监控支持。

  • kue:

    不要选择 kue 用于任何新项目。它已被官方明确标记为废弃(deprecated),不再接受功能更新或安全修复。现有项目应制定迁移计划,转向 BullMQ 或其他活跃维护的替代方案。

  • node-resque:

    选择 node-resque 仅当你有 Ruby Resque 的使用经验,或需要与现有 Resque 生态集成。它忠实复刻了 Resque 的概念模型,但文档和社区支持较弱,学习曲线较陡。对于大多数新项目,BullMQ 是更高效的选择。

bullmq的README



The fastest, most reliable, Redis-based distributed queue for Node.
Carefully written for rock solid stability and atomicity.

Read the documentation

Follow @manast for *important* Bull/BullMQ/BullMQ-Pro news and updates!

🛠 Tutorials

You can find tutorials and news in this blog: https://blog.taskforce.sh/

News 🚀

🌐 Language agnostic BullMQ

Do you need to work with BullMQ on platforms other than Node.js? If so, check out the BullMQ Proxy

Official FrontEnd

Taskforce.sh, Inc

Supercharge your queues with a professional front end:

  • Get a complete overview of all your queues.
  • Inspect jobs, search, retry, or promote delayed jobs.
  • Metrics and statistics.
  • and many more features.

Sign up at Taskforce.sh

🚀 Sponsors 🚀

Dragonfly Dragonfly is a new Redis™ drop-in replacement that is fully compatible with BullMQ and brings some important advantages over Redis™ such as massive better performance by utilizing all CPU cores available and faster and more memory efficient data structures. Read more here on how to use it with BullMQ.

Used by

Some notable organizations using BullMQ:

Microsoft Vendure Datawrapper Nest Langfuse
Curri Novu NoCodeDB Infisical

The gist

Install:

$ yarn add bullmq

Add jobs to the queue:

import { Queue } from 'bullmq';

const queue = new Queue('Paint');

queue.add('cars', { color: 'blue' });

Process the jobs in your workers:

import { Worker } from 'bullmq';

const worker = new Worker('Paint', async job => {
  if (job.name === 'cars') {
    await paintCar(job.data.color);
  }
});

Listen to jobs for completion:

import { QueueEvents } from 'bullmq';

const queueEvents = new QueueEvents('Paint');

queueEvents.on('completed', ({ jobId }) => {
  console.log('done painting');
});

queueEvents.on(
  'failed',
  ({ jobId, failedReason }: { jobId: string; failedReason: string }) => {
    console.error('error painting', failedReason);
  },
);

Adds jobs with parent-child relationship:

import { FlowProducer } from 'bullmq';

const flow = new FlowProducer();

const originalTree = await flow.add({
  name: 'root-job',
  queueName: 'topQueueName',
  data: {},
  children: [
    {
      name: 'child-job',
      data: { idx: 0, foo: 'bar' },
      queueName: 'childrenQueueName',
      children: [
        {
          name: 'grandchild-job',
          data: { idx: 1, foo: 'bah' },
          queueName: 'grandChildrenQueueName',
        },
        {
          name: 'grandchild-job',
          data: { idx: 2, foo: 'baz' },
          queueName: 'grandChildrenQueueName',
        },
      ],
    },
    {
      name: 'child-job',
      data: { idx: 3, foo: 'foo' },
      queueName: 'childrenQueueName',
    },
  ],
});

This is just scratching the surface, check all the features and more in the official documentation

Feature Comparison

Since there are a few job queue solutions, here is a table comparing them:

FeatureBullMQ-ProBullMQBullKueBeeAgenda
Backendredisredisredisredisredismongo
Observables
Group Rate Limit
Group Support
Batches Support
Parent/Child Dependencies
Deduplication (Debouncing)
Deduplication (Throttling)
Priorities
Concurrency
Delayed jobs
Global events
Rate Limiter
Pause/Resume
Sandboxed worker
Repeatable jobs
Atomic ops
Persistence
UI
Optimized forJobs / MessagesJobs / MessagesJobs / MessagesJobsMessagesJobs

Contributing

Fork the repo, make some changes, submit a pull-request! Here is the contributing doc that has more details.

Thanks

Thanks for all the contributors that made this library possible, also a special mention to Leon van Kammen that kindly donated his npm bullmq repo.