从零入门 NestJS:构建你的第一个 REST API(八)结合 Bull 的消息队列

343 阅读4分钟

结合 Bull 的消息队列

在实际开发中,很多任务(如邮件发送、图片处理、数据导出等)不适合在主请求流程中同步执行。消息队列可以将这些耗时操作异步化,提升系统响应速度和可扩展性。NestJS 推荐使用 Bull 作为队列解决方案。

消息队列架构图示意

下图展示了在 NestJS 项目中,Bull + Redis 消息队列的典型架构与数据流转流程:

NestJS Bull 消息队列架构图

流程说明:

  1. 用户请求到达 Controller,业务 Service 通过 Producer 将任务添加到队列(Redis)。
  2. Redis 作为消息队列存储所有待处理任务。
  3. Consumer(Processor)从队列中取出任务,进行异步处理(如发送邮件、生成报表等)。
  4. 处理结果可通过回调、通知等方式反馈。

Bull 简介

Bull 是基于 Redis 的高性能消息队列,支持任务重试、延迟、优先级、并发等特性,适合 Node.js 场景下的异步任务处理。

  • 支持任务持久化、失败重试、定时任务、任务优先级等
  • 依赖 Redis,易于部署和扩展
  • 与 NestJS 有官方集成包 @nestjs/bull

安装与环境准备

  1. 安装依赖:
npm install --save @nestjs/bull bull ioredis
  1. 本地需有 Redis 服务(可用 Docker 快速启动):
docker run -p 6379:6379 redis

在 NestJS 中集成 Bull

在主模块中引入 BullModule 并配置 Redis 连接:

// app.module.ts
import { Module } from '@nestjs/common';
import { BullModule } from '@nestjs/bull';
import { MailModule } from './mail/mail.module';

@Module({
  imports: [
    BullModule.forRoot({
      redis: {
        host: 'localhost',
        port: 6379,
      },
    }),
    MailModule,
  ],
})
export class AppModule {}

创建队列与任务生产者

// mail/mail.module.ts
import { Module } from '@nestjs/common';
import { BullModule } from '@nestjs/bull';
import { MailService } from './mail.service';
import { MailProcessor } from './mail.processor';

@Module({
  imports: [
    BullModule.registerQueue({ name: 'mail' }),
  ],
  providers: [MailService, MailProcessor],
  exports: [MailService],
})
export class MailModule {}
// mail/mail.service.ts
import { Injectable } from '@nestjs/common';
import { InjectQueue } from '@nestjs/bull';
import { Queue } from 'bull';

@Injectable()
export class MailService {
  constructor(@InjectQueue('mail') private mailQueue: Queue) {}

  async sendMail(to: string, subject: string, content: string) {
    // 添加任务到队列
    await this.mailQueue.add('send', { to, subject, content });
  }
}

创建任务消费者(Processor)

// mail/mail.processor.ts
import { Process, Processor } from '@nestjs/bull';
import { Job } from 'bull';

@Processor('mail')
export class MailProcessor {
  @Process('send')
  async handleSendMail(job: Job) {
    const { to, subject, content } = job.data;
    // 实际发送邮件逻辑(可调用第三方服务)
    console.log(`发送邮件到: ${to}, 主题: ${subject}`);
    // ...
  }
}

典型实战场景:异步邮件发送

在用户注册、下单等场景下,调用 MailService.sendMail 即可异步发送邮件,无需等待任务完成即可响应用户。

// user.service.ts
import { Injectable } from '@nestjs/common';
import { MailService } from '../mail/mail.service';

@Injectable()
export class UserService {
  constructor(private readonly mailService: MailService) {}

  async register(username: string, email: string) {
    // ...注册逻辑
    await this.mailService.sendMail(email, '欢迎注册', '感谢您的加入!');
    return { message: '注册成功' };
  }
}

进阶用法与最佳实践

  • 任务重试与失败处理:可在 add 方法中设置重试次数、延迟等参数。
  • 定时/延迟任务:如定时发送通知、延迟执行任务。
  • 任务优先级与并发:支持设置任务优先级和并发消费数。
  • 队列监控:可集成 bull-board 等可视化工具监控任务状态。
  • 错误处理:在 Processor 中捕获异常,避免任务丢失。
  • 合理拆分队列:不同业务建议用不同队列,便于扩展和监控。

1. 延迟任务与定时任务

// 延迟5分钟后发送通知
await this.mailQueue.add('send', { to, subject, content }, { delay: 5 * 60 * 1000 });

// 定时任务:每天8点发送(需结合 cron 表达式)
await this.mailQueue.add('send', { to, subject, content }, { repeat: { cron: '0 8 * * *' } });

2. 任务重试

// 失败后最多重试3次,每次间隔10秒
await this.mailQueue.add('send', { to, subject, content }, { attempts: 3, backoff: 10000 });

3. 集成 bull-board 可视化监控

bull-board 是 Bull 官方推荐的 Web UI,可实时查看队列、任务状态、失败原因等。

  1. 安装依赖:
npm install --save bull-board
  1. 在 main.ts 或专用模块中集成:
// main.ts
import { createBullBoard } from 'bull-board';
import { BullAdapter } from 'bull-board/bullAdapter';
import { Queue } from 'bull';
import { getQueueToken } from '@nestjs/bull';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  const mailQueue = app.get<Queue>(getQueueToken('mail'));
  const { router } = createBullBoard([
    new BullAdapter(mailQueue),
  ]);
  app.use('/admin/queues', router);
  await app.listen(3000);
}
  • 启动后访问 http://localhost:3000/admin/queues 即可查看队列状态。

常见坑点

  • Redis 未启动或连接异常,队列功能无法使用。
  • Processor 未注册或命名不一致,任务无法被消费。
  • 任务数据过大或频繁,需关注 Redis 性能瓶颈。
  • 未处理任务失败和重试,可能导致消息丢失。

Bull 让异步任务处理变得简单高效,建议多查阅 Bull 官方文档@nestjs/bull 文档 掌握更多高级用法。