Asynchronous Architecture: Message Queues and Background Tasks

HARD8 min readby AdminJune 19, 2026History
0.0|0 ratingsLog in to rate

Optimize server performance and scale systems by offloading heavy computational tasks onto asynchronous message queues.

#backend#architecture#message-queue#redis#bullmq

Why Use Message Queues?

In standard HTTP routers, a request must be answered within milliseconds. If a user triggers a long-running action (like video processing, bulk PDF generation, or bulk email notifications), handling it synchronously blocks the server thread and degrades UX.

A Message Queue offloads this work. The web server acting as a Producer pushes job metadata into a queue (e.g. Redis/BullMQ, RabbitMQ). The server responds to the user immediately with 202 Accepted status codes (see HTTP Status Codes). A separate background worker process acting as a Consumer polls the queue and executes the job asynchronously.

BullMQ Producer & Consumer Example

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 1. PRODUCER (Express Server handler)
const { Queue } = require('bullmq');
const emailQueue = new Queue('email', { connection: redisConnection });

app.post('/api/register', async (req, res) => {
  // Register user in database
  await emailQueue.add('sendWelcome', { email: req.body.email });
  res.status(202).json({ message: 'User registered! Email queued.' });
});

// 2. CONSUMER (Background Worker Process)
const { Worker } = require('bullmq');
const emailWorker = new Worker('email', async job => {
  if (job.name === 'sendWelcome') {
    await sendEmailService(job.data.email);
    console.log(`Email dispatched to ${job.data.email}`);
  }
}, { connection: redisConnection });

Discussion

Join the discussion! Sign in to leave comments and ask questions.

Loading discussion...