10分钟上手Express.js任务队列:从阻塞到丝滑的后台处理方案
【免费下载链接】express 项目地址: https://gitcode.com/gh_mirrors/exp/express
你是否遇到过用户上传大文件时页面卡死?生成报表需要等待30秒以上?这些"卡壳"体验往往源于同步处理耗时任务。本文将带你用10分钟实现一个可靠的Express.js任务队列系统,彻底解决后台任务阻塞问题。
为什么需要任务队列?
当用户触发耗时操作(如视频转码、数据导出)时,同步处理会导致:
- ⏳ 接口超时(常见于30秒以上的任务)
- 🚫 服务器资源被独占,影响其他用户
- 💥 进程崩溃导致任务丢失
Express.js作为单线程模型,尤其需要任务队列来实现非阻塞I/O。通过将任务异步化,我们可以立即返回响应,让用户继续操作,后台默默完成工作。
实现方案:Bull + Express
虽然Express核心未内置任务队列,但我们可以通过成熟的社区方案快速集成。推荐使用Bull(基于Redis的高性能队列),它支持:
- ✅ 任务优先级
- ✅ 失败重试
- ✅ 任务进度跟踪
- ✅ 分布式处理
环境准备
首先克隆项目仓库并安装依赖:
git clone https://gitcode.com/gh_mirrors/exp/express.git
cd express
npm install bull redis
项目基础配置可参考package.json,当前Express版本为4.19.2,支持Node.js 0.10.0及以上版本。
核心实现步骤
1. 创建任务队列实例
在项目根目录新建queue.js:
const Queue = require('bull');
// 创建名为"email-queue"的队列,使用本地Redis
const emailQueue = new Queue('email-queue', 'redis://127.0.0.1:6379');
module.exports = { emailQueue };
2. 实现任务生产者(添加任务)
修改examples/mvc/controllers/user/index.js,添加邮件发送队列:
const { emailQueue } = require('../../../queue');
// 用户注册接口
exports.register = async (req, res) => {
try {
const user = await User.create(req.body);
// 添加任务到队列,而非直接发送
await emailQueue.add('welcome-email', {
userId: user.id,
email: user.email
}, {
attempts: 3, // 失败重试3次
backoff: { type: 'exponential', delay: 5000 } // 指数退避策略
});
res.redirect('/users');
} catch (err) {
res.status(500).render('error', { error: err });
}
};
完整的MVC架构参考examples/mvc/index.js,该示例展示了如何组织控制器、中间件和视图。
3. 实现任务消费者(处理任务)
新建workers/email-worker.js:
const { emailQueue } = require('../queue');
const nodemailer = require('nodemailer');
// 创建邮件 transporter
const transporter = nodemailer.createTransport({
host: 'smtp.example.com',
port: 587,
secure: false,
auth: {
user: 'your-email@example.com',
pass: 'your-password'
}
});
// 处理队列中的任务
emailQueue.process('welcome-email', async (job) => {
const { userId, email } = job.data;
// 获取用户信息
const user = await User.findById(userId);
// 发送邮件
await transporter.sendMail({
to: email,
subject: 'Welcome to Our Service',
html: `<h1>Hello ${user.name}!</h1>`
});
return { success: true, userId };
});
// 监听任务完成事件
emailQueue.on('completed', (job, result) => {
console.log(`Job ${job.id} completed with result:`, result);
});
// 监听失败事件
emailQueue.on('failed', (job, err) => {
console.log(`Job ${job.id} failed with error:`, err);
});
4. 启动工作进程
修改package.json添加启动脚本:
"scripts": {
"start": "node index.js",
"worker": "node workers/email-worker.js"
}
分别启动Web服务和工作进程:
npm start
npm run worker
进阶配置
任务监控面板
安装Bull Board可视化监控队列状态:
npm install @bull-board/express
在app.js中添加监控路由:
const { createBullBoard } = require('@bull-board/api');
const { BullAdapter } = require('@bull-board/api/bullAdapter');
const { ExpressAdapter } = require('@bull-board/express');
const { emailQueue } = require('./queue');
const serverAdapter = new ExpressAdapter();
createBullBoard({
queues: [new BullAdapter(emailQueue)],
serverAdapter: serverAdapter
});
// 添加监控路由(生产环境需添加认证)
app.use('/admin/queues', serverAdapter.getRouter());
访问http://localhost:3000/admin/queues即可查看队列状态,包括等待中的任务、处理中的任务和失败任务。
分布式部署
在多服务器环境下,只需确保:
- 所有实例连接同一Redis服务器
- 工作进程可独立扩展(根据任务量调整数量)
最佳实践
- 错误处理:Always设置
attempts和backoff策略,参考Bull文档 - 任务持久化:关键任务需记录到数据库,实现最终一致性
- 资源隔离:不同类型任务使用独立队列,避免相互影响
- 监控告警:通过
failed事件配置告警通知(邮件/Slack)
总结
通过Bull + Express的组合,我们实现了:
- 🚀 非阻塞的用户体验
- 🛡️ 任务失败自动重试
- 📊 可视化监控和管理
- 📈 轻松扩展的分布式架构
这种模式不仅适用于邮件发送,还可广泛应用于文件处理、数据计算、定时任务等场景。立即集成到你的Express项目中,告别后台任务阻塞烦恼!
更多Express最佳实践可参考Contributing.md和Collaborator-Guide.md。
如果觉得本文有帮助,别忘了点赞收藏,关注作者获取更多Node.js实战技巧!下一期我们将探讨如何实现定时任务和任务优先级调度。
【免费下载链接】express 项目地址: https://gitcode.com/gh_mirrors/exp/express
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



