Giới thiệu vấn đề
Trong các ứng dụng backend hiện đại, việc xử lý hàng triệu yêu cầu đồng thời đòi hỏi phải tách các tác vụ nặng ra khỏi luồng phản hồi HTTP. Nếu thực hiện trực tiếp trong route, server sẽ bị block, thời gian phản hồi tăng lên và trải nghiệm người dùng giảm sút. Giải pháp phổ biến là sử dụng queue để đưa các công việc nền (background jobs) vào một hàng đợi, cho phép xử lý bất đồng bộ và mở rộng quy mô dễ dàng.
Khái niệm Queue và BullMQ
Queue là cấu trúc dữ liệu lưu trữ các công việc cần thực hiện theo thứ tự FIFO. Trong môi trường Node.js, BullMQ là thư viện mạnh mẽ dựa trên Redis, cung cấp API hiện đại để tạo, quản lý và giám sát các hàng đợi. BullMQ hỗ trợ tính năng retry, back‑off, delayed jobs và tích hợp dễ dàng với các worker.
Cài đặt và cấu hình
Đầu tiên, cài đặt BullMQ và driver Redis (ioredis) bằng npm:
npm install bullmq ioredis
Sau khi cài đặt, tạo một file queue.js để khởi tạo kết nối Redis và định nghĩa queue:
const { Queue, Worker, QueueScheduler } = require('bullmq');
const IORedis = require('ioredis');
const connection = new IORedis({
host: '127.0.0.1',
port: 6379
});
const myQueue = new Queue('emailQueue', { connection });
new QueueScheduler('emailQueue', { connection });
Tạo Producer (đưa công việc vào queue)
Producer chịu trách nhiệm thêm công việc vào queue. Dưới đây là hàm addEmailJob thêm một email vào hàng đợi với cấu hình retry và back‑off:
async function addEmailJob(data) {
await myQueue.add('sendEmail', data, {
attempts: 5,
backoff: {
type: 'exponential',
delay: 5000
}
});
}
// Ví dụ sử dụng
addEmailJob({ to: '[email protected]', subject: 'Welcome', body: 'Hello!' });
Worker xử lý công việc nền
Worker lắng nghe các job trong queue và thực thi chúng. Khi một job thất bại, BullMQ sẽ tự động retry theo cấu hình ở trên. Dưới đây là một worker đơn giản gửi email:
const worker = new Worker('emailQueue', async job => {
const { to, subject, body } = job.data;
// Giả sử hàm sendMail đã được định nghĩa ở đâu đó
await sendMail(to, subject, body);
}, { connection });
worker.on('failed', (job, err) => {
console.error(`Job ${job.id} failed:`, err);
});
Quản lý lỗi và retry
Trong ví dụ trên, tùy chọn attempts và backoff giúp tự động thử lại khi gửi email thất bại (ví dụ do lỗi mạng). Bạn cũng có thể lắng nghe các sự kiện completed, failed, stalled để ghi log hoặc thực hiện hành động bổ sung.
Giám sát Queue với Bull Board
Để theo dõi trạng thái các job, Bull Board cung cấp giao diện web đơn giản. Cài đặt và cấu hình như sau:
const { createBullBoard } = require('@bull-board/api');
const { BullMQAdapter } = require('@bull-board/api/bullMQAdapter');
const { ExpressAdapter } = require('@bull-board/express');
const serverAdapter = new ExpressAdapter();
createBullBoard({
queues: [new BullMQAdapter(myQueue)],
serverAdapter
});
app.use('/admin/queues', serverAdapter.getRouter());
Sau khi khởi động server, truy cập /admin/queues để xem số lượng job đang chờ, đang chạy, đã hoàn thành và các lỗi.
Kết luận
Việc tích hợp BullMQ với Redis giúp bạn xây dựng một hệ thống xử lý công việc nền mạnh mẽ, có khả năng mở rộng và chịu lỗi cao. Khi áp dụng đúng mô hình queue, các API của bạn sẽ phản hồi nhanh hơn, đồng thời các tác vụ nặng như gửi email, xử lý ảnh hay tạo báo cáo sẽ được thực hiện một cách ổn định.
Để nắm vững toàn bộ quy trình từ thiết kế kiến trúc, triển khai tới giám sát, Tham khảo khóa học "Lập trình Back-End với NodeJS Express" tại đây.








