引言:为什么需要任务队列?
想象一下,您在 Node.js 上运行一个 Web 服务器。用户发送一个请求,要求发送 1000 封电子邮件。如果同步处理此请求,服务器将“挂起”几分钟——所有其他用户将无法得到响应。
如何解决这个问题?答案是 任务队列 (task queues)。它们允许您推迟执行资源密集型操作(如发送邮件、生成 PDF、处理图像),并在后台执行它们,而不会阻塞应用程序的主线程。
在本文中,我们将介绍:
- 什么是任务队列及其工作原理
- Node.js 的流行库(Bull、Kue)
- 代码示例:创建、添加和处理任务
- 面向初学者的最佳实践
1. Node.js 任务队列基础
什么是任务队列?
任务队列是一种数据结构,遵循 FIFO(先进先出)原则。任务被添加到队列的末尾,并从队列的开头进行处理。队列通常基于 Redis 构建——一种快速的内存键值存储。
队列的主要组件:
- 生产者 (Producer) — 将任务添加到队列的代码
- 消费者 (Worker) — 从队列中取出并执行任务的代码
- 队列管理器 (Queue Manager) — 管理队列的机制(通常是 Redis)
流行的库
Node.js 有两个主要的库:
- Bull — 现代、快速,支持优先级、重试和延迟
- Kue — 较旧但简单的库(现在不太流行)
本文将重点介绍 Bull,因为它得到积极维护并且功能更丰富。
2. 安装和配置 Bull
步骤 1:安装 Redis
Bull 使用 Redis。如果您没有 Redis,请安装它:
# macOSbrew install redis
# Ubuntusudo apt-get install redis-server
# 启动 Redisredis-server步骤 2:安装 Bull
创建一个新项目并安装该包:
mkdir queue-democd queue-demonpm init -ynpm install bull步骤 3:基本配置
创建文件 queue.js:
const Queue = require('bull');
// 创建一个名为 'emailQueue' 的队列const emailQueue = new Queue('emailQueue', { redis: { host: '127.0.0.1', port: 6379 }});
module.exports = emailQueue;3. 示例:用于发送电子邮件的队列
步骤 1:创建生产者(添加任务)
创建文件 producer.js:
const emailQueue = require('./queue');
async function addEmailTask(to, subject, body) { // 将任务添加到队列 const job = await emailQueue.add({ to: to, subject: subject, body: body }, { // 任务选项 attempts: 3, // 出错时的重试次数 backoff: 5000, // 重试之间的延迟(5 秒) delay: 1000 // 执行前的延迟(1 秒) });
console.log(`任务已添加,ID: ${job.id}`); return job;}
// 使用示例addEmailTask('user@example.com', '你好!', '测试消息');步骤 2:创建消费者(处理任务)
创建文件 worker.js:
const emailQueue = require('./queue');
// 模拟发送电子邮件的函数async function sendEmail(to, subject, body) { console.log(`正在向 ${to} 发送邮件...`); // 模拟延迟 await new Promise(resolve => setTimeout(resolve, 2000)); console.log(`邮件已发送: ${subject}`);}
// 队列处理器emai