- vừa được xem lúc

# Quản lý Queue trong NestJS

0 0 3

Người đăng: Dao Vinh Sơn

Theo Viblo Asia

Giới thiệu

Trong các hệ thống backend hiện đại, việc xử lý các tác vụ bất đồng bộ là một nhu cầu thiết yếu. Các tác vụ như gửi email, xử lý ảnh, tạo báo cáo PDF, gửi notification, hoặc đồng bộ dữ liệu thường không nên thực hiện trực tiếp trong quá trình phản hồi client. Điều này ảnh hưởng đến hiệu suất và trải nghiệm người dùng. Để giải quyết vấn đề này, chúng ta sử dụng queue – một hàng đợi chứa các công việc (jobs) cần được xử lý bất đồng bộ.

Trong hệ sinh thái của NestJS, framework nổi bật trong thế giới Node.js, việc tích hợp queue rất dễ dàng thông qua thư viện @nestjs/bull, một wrapper của Bull – một thư viện dựa trên Redis, mạnh mẽ và đáng tin cậy để xử lý hàng đợi.

Trong bài viết này, bạn sẽ được hướng dẫn toàn diện về cách triển khai, sử dụng và mở rộng queue trong NestJS, kèm theo ví dụ thực tế và các giải thích chi tiết về từng bước triển khai.


Mục lục

  1. Queue là gì?
  2. Tại sao nên dùng queue trong NestJS?
  3. Kiến trúc tổng thể khi sử dụng queue
  4. Cài đặt Bull trong NestJS
  5. Tạo producer (đẩy job vào hàng đợi)
  6. Tạo processor (xử lý job từ hàng đợi)
  7. Các tính năng nâng cao trong Bull
  8. Giao diện quản trị với Bull Board
  9. Lưu ý và best practices
  10. Tổng kết

1. Queue là gì?

Queue (hàng đợi) là một cấu trúc dữ liệu tuyến tính tuân theo nguyên tắc FIFO (First In – First Out). Trong bối cảnh backend, queue thường dùng để quản lý các công việc (job) đợi được xử lý bởi một hoặc nhiều worker.

Ví dụ: Khi người dùng đăng ký tài khoản, ta có thể gửi email xác nhận qua một job nằm trong queue, thay vì gửi ngay trong luồng xử lý chính.

Mỗi job có thể chứa:

  • Dữ liệu (payload): ví dụ thông tin người dùng, URL ảnh, v.v.
  • Cấu hình: retry, delay, ưu tiên xử lý, ...

Worker sẽ lấy job ra khỏi hàng đợi và xử lý theo logic đã định nghĩa.


2. Tại sao nên dùng queue trong NestJS?

Một số lợi ích rõ rệt của việc dùng queue:

  • Tăng tốc phản hồi người dùng: Giảm độ trễ khi thực hiện tác vụ nặng.
  • Đảm bảo độ tin cậy: Có thể retry nếu job thất bại.
  • Tách biệt logic xử lý: Giúp code rõ ràng và dễ bảo trì hơn.
  • Giám sát dễ dàng: Có thể theo dõi job đang xử lý hoặc lỗi qua Bull Board.
  • Khả năng mở rộng: Các worker xử lý job có thể chạy ở nhiều node khác nhau.

3. Kiến trúc tổng thể khi sử dụng queue

Client ---> NestJS App (Producer) ---> Redis Queue ---> Worker (Processor) ---> Result
  • Producer: Tạo và đẩy job vào queue (ví dụ: gửi email, resize ảnh).
  • Queue: Redis lưu trữ job.
  • Processor: Nhận và xử lý job (chạy nền).
  • Worker: Có thể là process riêng, thuận tiện khi scale ngang.

4. Cài đặt Bull trong NestJS

4.1. Cài đặt package

npm install --save @nestjs/bull bull ioredis

Bull cần Redis để hoạt động nên hãy đảm bảo bạn có Redis đang chạy (có thể dùng Docker).

4.2. Cấu hình BullModule trong AppModule

import { BullModule } from '@nestjs/bull';
import { Module } from '@nestjs/common'; @Module({ imports: [ BullModule.forRoot({ redis: { host: 'localhost', port: 6379, }, }), ],
})
export class AppModule {}

Bạn có thể thay bằng biến môi trường để tiện deploy:

redis: { host: process.env.REDIS_HOST, port: parseInt(process.env.REDIS_PORT),
}

5. Tạo Producer

Producer là nơi tạo và đẩy job vào queue. Ví dụ, khi user đăng ký thì gửi email.

5.1. Đăng ký queue

// email.module.ts
import { BullModule } from '@nestjs/bull';
import { Module } from '@nestjs/common';
import { EmailService } from './email.service'; @Module({ imports: [ BullModule.registerQueue({ name: 'email', }), ], providers: [EmailService],
})
export class EmailModule {}

5.2. Service đẩy job

// email.service.ts
import { InjectQueue } from '@nestjs/bull';
import { Queue } from 'bull';
import { Injectable } from '@nestjs/common'; @Injectable()
export class EmailService { constructor(@InjectQueue('email') private readonly emailQueue: Queue) {} async sendWelcomeEmail(user: { email: string; name: string }) { await this.emailQueue.add('welcome', user, { attempts: 3, // Retry tối đa 3 lần backoff: 5000, // Delay 5s trước mỗi retry removeOnComplete: true, removeOnFail: false, // Giữ lại job lỗi để debug }); }
}

6. Tạo Processor

Processor là nơi định nghĩa cách xử lý từng loại job cụ thể.

// email.processor.ts
import { Process, Processor } from '@nestjs/bull';
import { Job } from 'bull';
import { Injectable } from '@nestjs/common'; @Processor('email')
@Injectable()
export class EmailProcessor { @Process('welcome') async handleWelcomeEmail(job: Job<{ email: string; name: string }>) { const { email, name } = job.data; console.log(`Sending welcome email to ${email}`); // Gọi hàm gửi email thật ở đây (SendGrid, Mailgun, v.v.) }
}

Đăng ký Processor trong module:

@Module({ imports: [BullModule.registerQueue({ name: 'email' })], providers: [EmailService, EmailProcessor],
})

7. Các tính năng nâng cao trong Bull

7.1. Delay job (trì hoãn xử lý)

await this.emailQueue.add('welcome', user, { delay: 30000, // 30s sau mới xử lý
});

7.2. Repeat job theo định kỳ (Cron)

await this.emailQueue.add('daily-summary', {}, { repeat: { cron: '0 8 * * *' }, // Mỗi ngày lúc 8h sáng
});

7.3. Job ưu tiên

await this.emailQueue.add('vip-welcome', user, { priority: 1, // Ưu tiên cao hơn job khác (mặc định = 5)
});

7.4. Job theo nhóm (jobId, grouping)

Bạn có thể gán jobId để dễ phân nhóm hoặc tránh tạo trùng job.

await this.emailQueue.add('task', payload, { jobId: `task-${payload.userId}`,
});

8. Bull Board – Giao diện quản trị queue

Bull Board là UI hiển thị các job đang xử lý, lỗi, pending,... rất trực quan.

8.1. Cài đặt

npm install --save bull-board

8.2. Tích hợp Bull Board

// main.ts
import { createBullBoard } from 'bull-board';
import { BullAdapter } from 'bull-board/bullAdapter';
import { ExpressAdapter } from 'bull-board/express';
import express from 'express'; async function bootstrap() { const app = await NestFactory.create(AppModule); const server = express(); const emailQueue = app.get<Queue>('BullQueue_email'); const serverAdapter = new ExpressAdapter(); serverAdapter.setBasePath('/admin/queues'); createBullBoard({ queues: [new BullAdapter(emailQueue)], serverAdapter, }); server.use('/admin/queues', serverAdapter.getRouter()); app.use(server); await app.listen(3000);
}

Sau khi chạy app, bạn có thể truy cập http://localhost:3000/admin/queues để theo dõi job.


9. Lưu ý và best practices

  • Tách Producer và Processor vào module riêng giúp dễ scale và maintain.
  • Với job không quan trọng, hãy đặt removeOnComplete: true để dọn Redis.
  • Đặt attemptsbackoff phù hợp để retry hiệu quả.
  • Log job fail để debug nguyên nhân.
  • Tránh gửi dữ liệu nhạy cảm trong job (sử dụng ID và truy xuất lại từ DB).
  • Với hệ thống lớn, có thể triển khai processor dạng microservice riêng biệt.
  • Dùng queue monitor (Bull Board hoặc custom dashboard) để giám sát hiệu quả.

10. Tổng kết

Queues là một phần không thể thiếu trong hệ thống backend hiện đại, giúp tăng hiệu năng, mở rộng tốt hơn và dễ bảo trì. Với sự hỗ trợ của NestJS và Bull, bạn có thể dễ dàng triển khai hàng đợi mạnh mẽ, giàu tính năng và dễ giám sát.

Tóm tắt kiến thức bạn đã học được:

  • Kiến thức cơ bản về queue và lý do cần sử dụng.
  • Cách tích hợp Bull queue vào dự án NestJS.
  • Triển khai producer và processor chuẩn chỉnh.
  • Áp dụng các tính năng nâng cao: delay, retry, cron, priority.
  • Giám sát hệ thống queue thông qua Bull Board.

Tài liệu tham khảo

Nếu bạn thấy bài viết hữu ích, hãy chia sẻ cho bạn bè hoặc đồng nghiệp đang dùng NestJS nhé!

Bình luận

Bài viết tương tự

- vừa được xem lúc

Cài đặt WSL / WSL2 trên Windows 10 để code như trên Ubuntu

Sau vài ba năm mình chuyển qua code trên Ubuntu thì thật không thể phủ nhận rằng mình đã yêu em nó. Cá nhân mình sử dụng Ubuntu để code web thì thật là tuyệt vời.

1 1 561

- vừa được xem lúc

Hướng dẫn làm bot Facebook messenger cho tài khoản cá nhân

Giới thiệu. Trong bài viết trước thì mình có hướng dẫn các bạn làm chatbot facebook messenger cho fanpage. Hôm nay mình sẽ hướng dẫn các bạn tạo chatbot cho một tài khoản facebook cá nhân. Chuẩn bị.

0 0 376

- vừa được xem lúc

Crawl website sử dụng Node.js và Puppeteer - phần 2

trong phần 1 mình đã giới thiệu về puppeteer và tạo được 1 project cùng một số file đầu tiên để các bạn có thể crawl dữ liệu từ một trang web bất kỳ. Bài này mình sẽ tiếp nối bài viết trước để hoàn thiện seri này.

0 0 79

- vừa được xem lúc

Điều React luôn giữ kín trong tim

■ Mở đầu. Ngồi viết bài khi đang nghĩ vu vơ chuyện con gà hay quả trứng có trước, mình phân vân chưa biết sẽ chọn chủ đề gì để chúng ta có thể cùng nhau bàn luận.

0 0 63

- vừa được xem lúc

Gửi Mail với Nodejs và AWS SES

AWS SES. AWS SES là gì.

0 0 89

- vừa được xem lúc

Crawl website sử dụng Node.js và Puppeteer - phần 1

Bài viết này mình sẽ giới thiệu cho các bạn craw dữ liệu của web site sử dụng nodejs và Puppeteer. .

0 0 168