Task Queues for TypeScript: Library Overview and Practical Implementation
In modern TypeScript web applications, there is often a need to perform resource-intensive operations asynchronously without blocking the main thread. Task queues (job queues) are used for this purpose. They allow you to defer execution, distribute load, and ensure reliable processing of background processes. In this article, we will review the best libraries for working with queues in TypeScript, their features, and usage examples.
Why are task queues needed?
Imagine your application needs to send 1000 emails, process images, or perform complex calculations. If done synchronously, the user would wait minutes for a response. A queue solves this problem: you place a task in a list, and a worker processes it in the background. Key benefits:
- Asynchrony and non-blocking processing
- Scalability (multiple workers can work in parallel)
- Fault tolerance (task restarts on error)
- Scheduling (tasks can be deferred to a specific time)
Top Libraries for TypeScript
Most popular solutions are built on Redis — a fast in-memory database ideally suited for queues. Let's look at three main options:
1. Bull (most popular)
Bull is a mature and performant library for Node.js with full TypeScript support. It provides a rich API and built-in mechanisms for retries, delays, and priorities.
Installation:
npm install bullnpm install @types/bullExample of creating a queue and handler:
import Queue from 'bull';
// Create a queue for processing email newslettersconst emailQueue = new Queue('email', { redis: { host: 'localhost', port: 6379 }});
// Add a taskasync function sendWelcomeEmail(userId: string) { await emailQueue.add({ userId });}
// Handler (worker)emailQueue.process(async (job) => { const { userId } = job.data; // Email sending logic here console.log(`Sending email to user ${userId}`); await sendEmail(userId);});
// Error handling and retriesemailQueue.on('failed', (job, err) => { console.error(`Job ${job.id} failed: ${err.message}`);});2. Bee-Queue (lightweight alternative)
Bee-Queue is a minimalist queue, also working on Redis. It is simpler than Bull but faster for simple scenarios. It's well-suited when complex configuration is not needed.
Installation:
npm install bee-queuenpm install @types/bee-queueExample:
import Queue from 'bee-queue';
const imageQueue = new Queue('images', { redis: { host: 'localhost', port: 6379 }});
// Add a taskimageQueue.createJob({ imagePath: '/uploads/photo.jpg' }).save();
// ProcessingimageQueue.process((job, done) => { const { imagePath } = job.data; // Image processing resizeImage(imagePath) .then(() => done()) .catch(done);});3. RSMQ (without a separate worker)
RSMQ (Redis Simple Message Queue) is a queue on pure Redis that does not require running a separate worker process. Tasks are processed via a pull mechanism. Ideal for microservice architecture.
Installation:
npm install rsmqExample:
import RedisSMQ from 'rsmq';
const rsmq = new RedisSMQ({ host: 'localhost', port: 6379 });
// Create a queueawait rsmq.createQueueAsync({ qname: 'tasks' });
// Send a messageawait rsmq.sendMessageAsync({ qname: 'tasks', message: '{"type":"process_payment"}' });
// Receive and process (in a loop)const message = await rsmq.receiveMessageAsync({ qname: 'tasks' });if (message.id) { console.log('Processing:',