bull vs agenda vs bree vs bee-queue vs kue vs node-resque
Job and Queue Management Comparison
3 Years
bullagendabreebee-queuekuenode-resqueSimilar Packages:
What's Job and Queue Management?

Job and Queue Management Libraries in Node.js provide tools for handling background tasks, scheduling jobs, and managing queues of tasks to be processed asynchronously. These libraries help improve application performance by offloading time-consuming tasks from the main event loop, allowing for better scalability and responsiveness. They offer features like job prioritization, retries, scheduling, and monitoring, making them essential for building efficient and reliable applications that handle asynchronous processing. These libraries are particularly useful for tasks like sending emails, processing images, or performing data migrations without blocking the main application flow.

Package Weekly Downloads Trend
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
bull1,005,001
16,109309 kB1459 months agoMIT
agenda124,413
9,567353 kB354-MIT
bree32,629
3,20090.5 kB36a year agoMIT
bee-queue22,309
3,965106 kB452 years agoMIT
kue17,400
9,457-2878 years agoMIT
node-resque11,399
1,401705 kB215 months agoApache-2.0
Feature Comparison: bull vs agenda vs bree vs bee-queue vs kue vs node-resque

Storage Backend

  • bull:

    bull uses Redis as its storage backend, offering both persistent and ephemeral job storage. It provides advanced features like job retries, delayed jobs, and rate limiting, making it suitable for applications that require robust queue management and reliability.

  • agenda:

    agenda uses MongoDB as its storage backend, which allows for persistent job storage, scheduling, and retrieval. This makes it suitable for applications that require long-term job storage and reliability, as jobs can be stored even if the application restarts.

  • bree:

    bree does not require any external storage backend, as it uses worker threads to execute jobs directly. This makes it lightweight and efficient for running jobs in memory, but it does not provide persistent job storage or queuing.

  • bee-queue:

    bee-queue uses Redis as its storage backend, providing fast and ephemeral job storage. It is designed for low-latency job processing, making it ideal for applications that need quick job execution without the overhead of persistent storage.

  • kue:

    kue uses Redis as its storage backend, providing persistent job storage with support for job prioritization and retries. It also includes a built-in UI for monitoring job progress, making it suitable for applications that need visual management of job queues.

  • node-resque:

    node-resque supports multiple storage backends, including Redis and MongoDB, allowing for flexible job storage options. It provides features like job scheduling, retries, and plugins, making it a versatile choice for applications that require a customizable queue system.

Job Scheduling

  • bull:

    bull supports job scheduling, including delayed jobs and recurring jobs (with additional plugins). It provides a robust queuing mechanism with support for job prioritization and retries, making it suitable for complex job workflows.

  • agenda:

    agenda supports advanced job scheduling, including recurring jobs, delayed jobs, and one-time jobs. It allows for flexible scheduling using cron-like syntax, making it suitable for applications that require complex scheduling capabilities.

  • bree:

    bree supports job scheduling using cron syntax, allowing for both one-time and recurring jobs. It leverages worker threads for executing scheduled jobs, providing better performance for CPU-intensive tasks.

  • bee-queue:

    bee-queue focuses on simple job queuing and does not provide built-in support for job scheduling. It is designed for fast, on-demand job processing rather than scheduled tasks.

  • kue:

    kue supports job scheduling with delayed jobs and prioritization. It allows for creating jobs with specific delay times and priority levels, making it suitable for applications that require controlled job execution.

  • node-resque:

    node-resque supports job scheduling, including delayed jobs and recurring jobs, through its flexible API. It allows for creating jobs with specified delays and supports custom scheduling logic, making it a versatile choice for time-based job execution.

UI and Monitoring

  • bull:

    bull does not provide a built-in UI for monitoring jobs, but it allows for integration with external monitoring tools. Developers can create custom dashboards to visualize job status and metrics using the data stored in Redis.

  • agenda:

    agenda does not provide a built-in UI for monitoring jobs, but it allows for integration with external monitoring tools. Developers can create custom dashboards to visualize job status and metrics using the data stored in MongoDB.

  • bree:

    bree does not include a built-in UI for monitoring jobs, but it provides detailed logging and event hooks that can be used to track job execution. Developers can integrate third-party monitoring tools for better visibility.

  • bee-queue:

    bee-queue provides a simple API for monitoring job status, but it does not include a built-in UI. Developers can create custom monitoring solutions using the provided API to track job progress and failures.

  • kue:

    kue includes a built-in UI for monitoring job queues, displaying job status, progress, and failure rates. The UI provides a visual representation of job queues, making it easy to manage and monitor jobs in real-time.

  • node-resque:

    node-resque does not provide a built-in UI, but it allows for integration with external monitoring tools. Developers can create custom dashboards to visualize job status and metrics using the data stored in the chosen backend.

Job Retries

  • bull:

    bull supports advanced job retries with configurable retry limits, backoff strategies, and failure handling. It provides robust support for handling failed jobs and implementing complex retry logic.

  • agenda:

    agenda supports job retries in case of failure, allowing developers to configure retry logic and failure handling. It provides hooks for handling failed jobs and implementing custom retry strategies.

  • bree:

    bree supports job retries through custom implementation, but it does not provide built-in retry functionality. Developers can implement their own retry logic using the provided job events and hooks.

  • bee-queue:

    bee-queue supports job retries with configurable retry limits. It allows for automatic retries of failed jobs, making it suitable for handling transient errors in job processing.

  • kue:

    kue supports job retries with configurable retry limits and failure handling. It allows for automatic retries of failed jobs, making it suitable for handling errors and ensuring job completion.

  • node-resque:

    node-resque supports job retries with configurable retry limits and backoff strategies. It provides flexible failure handling and allows for custom retry logic to be implemented.

Ease of Use: Code Examples

  • bull:

    Simple Job Queue with bull

    const Queue = require('bull');
    const myQueue = new Queue('my-queue');
    
    // Process jobs
    myQueue.process(async (job) => {
      console.log(`Processing job ${job.id}`);
    });
    
    // Add a job to the queue
    myQueue.add({ data: 'my data' });
    
  • agenda:

    Simple Job Scheduling with agenda

    const Agenda = require('agenda');
    const mongoConnectionString = 'mongodb://localhost:27017/agenda';
    const agenda = new Agenda({ db: { address: mongoConnectionString } });
    
    // Define a job
    agenda.define('send email', async (job) => {
      console.log('Sending email...');
    });
    
    // Schedule a job
    agenda.schedule('in 10 seconds', 'send email');
    
    // Start the agenda
    agenda.start();
    
  • bree:

    Simple Job Scheduling with bree

    const Bree = require('bree');
    const bree = new Bree({
      jobs: [{
        name: 'my-job',
        interval: '10s',
      }],
    });
    
    // Start the scheduler
    bree.start();
    
  • bee-queue:

    Simple Job Queue with bee-queue

    const Queue = require('bee-queue');
    const queue = new Queue('my-queue');
    
    // Process jobs
    queue.process(async (job) => {
      console.log(`Processing job ${job.id}`);
    });
    
    // Add a job to the queue
    queue.createJob({ data: 'my data' }).save();
    
  • kue:

    Simple Job Queue with kue

    const kue = require('kue');
    const queue = kue.createQueue();
    
    // Create a job
    const job = queue.create('email', { to: 'example@example.com' }).save();
    
    // Process the job
    queue.process('email', (job, done) => {
      console.log(`Sending email to ${job.data.to}`);
      done();
    });
    
  • node-resque:

    Simple Job Queue with node-resque

    const { Queue, Worker } = require('node-resque');
    const queue = new Queue({
      myQueue: { jobs: ['myJob'] },
    });
    const worker = new Worker({ queue });
    
    // Define a job
    worker.on('myJob', (job, done) => {
      console.log(`Processing job ${job.id}`);
      done();
    });
    
    // Start the worker
    worker.start();
    
How to Choose: bull vs agenda vs bree vs bee-queue vs kue vs node-resque
  • bull:

    Choose bull if you need a feature-rich queue system with Redis support that offers advanced features like job retries, rate limiting, and delayed jobs. It is suitable for applications that require robust queue management and scalability.

  • agenda:

    Choose agenda if you need a job scheduler with MongoDB integration that supports recurring jobs, delayed jobs, and job prioritization. It is ideal for applications that require flexible scheduling and persistence of job states.

  • bree:

    Choose bree if you want a modern job scheduler that uses worker threads for executing jobs, providing better performance and resource utilization. It is ideal for applications that need to run CPU-intensive tasks without blocking the event loop.

  • bee-queue:

    Choose bee-queue if you need a simple and lightweight queue system with Redis support, focusing on performance and low latency. It is suitable for applications that require fast job processing with minimal overhead.

  • kue:

    Choose kue if you need a priority job queue backed by Redis with a built-in UI for monitoring jobs. It is ideal for applications that require visual monitoring and management of job queues.

  • node-resque:

    Choose node-resque if you need a flexible and extensible job queue system that supports multiple backends (Redis, MongoDB, etc.) and provides features like job scheduling, retries, and plugins. It is suitable for applications that require a highly customizable queue system.

README for bull



The fastest, most reliable, Redis-based queue for Node.
Carefully written for rock solid stability and atomicity.


Sponsors · Features · UIs · Install · Quick Guide · Documentation

Check the new Guide!


🚀 Sponsors 🚀

Dragonfly Dragonfly is a new Redis™ drop-in replacement that is fully compatible with BullMQ and brings some important advantages over Redis™ such as massive better performance by utilizing all CPU cores available and faster and more memory efficient data structures. Read more here on how to use it with BullMQ.

📻 News and updates

Bull is currently in maintenance mode, we are only fixing bugs. For new features check BullMQ, a modern rewritten implementation in Typescript. You are still very welcome to use Bull if it suits your needs, which is a safe, battle tested library.

Follow me on Twitter for other important news and updates.

🛠 Tutorials

You can find tutorials and news in this blog: https://blog.taskforce.sh/


Used by

Bull is popular among large and small organizations, like the following ones:

Atlassian Autodesk Mozilla Nest Salesforce


Official FrontEnd

Taskforce.sh, Inc

Supercharge your queues with a professional front end:

  • Get a complete overview of all your queues.
  • Inspect jobs, search, retry, or promote delayed jobs.
  • Metrics and statistics.
  • and many more features.

Sign up at Taskforce.sh


Bull Features

  • [x] Minimal CPU usage due to a polling-free design.
  • [x] Robust design based on Redis.
  • [x] Delayed jobs.
  • [x] Schedule and repeat jobs according to a cron specification.
  • [x] Rate limiter for jobs.
  • [x] Retries.
  • [x] Priority.
  • [x] Concurrency.
  • [x] Pause/resume—globally or locally.
  • [x] Multiple job types per queue.
  • [x] Threaded (sandboxed) processing functions.
  • [x] Automatic recovery from process crashes.

And coming up on the roadmap...

  • [ ] Job completion acknowledgement (you can use the message queue pattern in the meantime).
  • [ ] Parent-child jobs relationships.

UIs

There are a few third-party UIs that you can use for monitoring:

BullMQ

Bull v3

Bull <= v2


Monitoring & Alerting


Feature Comparison

Since there are a few job queue solutions, here is a table comparing them:

| Feature | BullMQ-Pro | BullMQ | Bull | Kue | Bee | Agenda | | :------------------------ | :-------------: | :-------------: | :-------------: | :---: | -------- | ------ | | Backend | redis | redis | redis | redis | redis | mongo | | Observables | ✓ | | | | | | | Group Rate Limit | ✓ | | | | | | | Group Support | ✓ | | | | | | | Batches Support | ✓ | | | | | | | Parent/Child Dependencies | ✓ | ✓ | | | | | | Priorities | ✓ | ✓ | ✓ | ✓ | | ✓ | | Concurrency | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Delayed jobs | ✓ | ✓ | ✓ | ✓ | | ✓ | | Global events | ✓ | ✓ | ✓ | ✓ | | | | Rate Limiter | ✓ | ✓ | ✓ | | | | | Pause/Resume | ✓ | ✓ | ✓ | ✓ | | | | Sandboxed worker | ✓ | ✓ | ✓ | | | | | Repeatable jobs | ✓ | ✓ | ✓ | | | ✓ | | Atomic ops | ✓ | ✓ | ✓ | | ✓ | | | Persistence | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | UI | ✓ | ✓ | ✓ | ✓ | | ✓ | | Optimized for | Jobs / Messages | Jobs / Messages | Jobs / Messages | Jobs | Messages | Jobs |

Install

npm install bull --save

or

yarn add bull

Requirements: Bull requires a Redis version greater than or equal to 2.8.18.

Typescript Definitions

npm install @types/bull --save-dev
yarn add --dev @types/bull

Definitions are currently maintained in the DefinitelyTyped repo.

Contributing

We welcome all types of contributions, either code fixes, new features or doc improvements. Code formatting is enforced by prettier. For commits please follow conventional commits convention. All code must pass lint rules and test suites before it can be merged into develop.


Quick Guide

Basic Usage

const Queue = require('bull');

const videoQueue = new Queue('video transcoding', 'redis://127.0.0.1:6379');
const audioQueue = new Queue('audio transcoding', { redis: { port: 6379, host: '127.0.0.1', password: 'foobared' } }); // Specify Redis connection using object
const imageQueue = new Queue('image transcoding');
const pdfQueue = new Queue('pdf transcoding');

videoQueue.process(function (job, done) {

  // job.data contains the custom data passed when the job was created
  // job.id contains id of this job.

  // transcode video asynchronously and report progress
  job.progress(42);

  // call done when finished
  done();

  // or give an error if error
  done(new Error('error transcoding'));

  // or pass it a result
  done(null, { framerate: 29.5 /* etc... */ });

  // If the job throws an unhandled exception it is also handled correctly
  throw new Error('some unexpected error');
});

audioQueue.process(function (job, done) {
  // transcode audio asynchronously and report progress
  job.progress(42);

  // call done when finished
  done();

  // or give an error if error
  done(new Error('error transcoding'));

  // or pass it a result
  done(null, { samplerate: 48000 /* etc... */ });

  // If the job throws an unhandled exception it is also handled correctly
  throw new Error('some unexpected error');
});

imageQueue.process(function (job, done) {
  // transcode image asynchronously and report progress
  job.progress(42);

  // call done when finished
  done();

  // or give an error if error
  done(new Error('error transcoding'));

  // or pass it a result
  done(null, { width: 1280, height: 720 /* etc... */ });

  // If the job throws an unhandled exception it is also handled correctly
  throw new Error('some unexpected error');
});

pdfQueue.process(function (job) {
  // Processors can also return promises instead of using the done callback
  return pdfAsyncProcessor();
});

videoQueue.add({ video: 'http://example.com/video1.mov' });
audioQueue.add({ audio: 'http://example.com/audio1.mp3' });
imageQueue.add({ image: 'http://example.com/image1.tiff' });

Using promises

Alternatively, you can return promises instead of using the done callback:

videoQueue.process(function (job) { // don't forget to remove the done callback!
  // Simply return a promise
  return fetchVideo(job.data.url).then(transcodeVideo);

  // Handles promise rejection
  return Promise.reject(new Error('error transcoding'));

  // Passes the value the promise is resolved with to the "completed" event
  return Promise.resolve({ framerate: 29.5 /* etc... */ });

  // If the job throws an unhandled exception it is also handled correctly
  throw new Error('some unexpected error');
  // same as
  return Promise.reject(new Error('some unexpected error'));
});

Separate processes

The process function can also be run in a separate process. This has several advantages:

  • The process is sandboxed so if it crashes it does not affect the worker.
  • You can run blocking code without affecting the queue (jobs will not stall).
  • Much better utilization of multi-core CPUs.
  • Less connections to redis.

In order to use this feature just create a separate file with the processor:

// processor.js
module.exports = function (job) {
  // Do some heavy work

  return Promise.resolve(result);
}

And define the processor like this:

// Single process:
queue.process('/path/to/my/processor.js');

// You can use concurrency as well:
queue.process(5, '/path/to/my/processor.js');

// and named processors:
queue.process('my processor', 5, '/path/to/my/processor.js');

Repeated jobs

A job can be added to a queue and processed repeatedly according to a cron specification:

  paymentsQueue.process(function (job) {
    // Check payments
  });

  // Repeat payment job once every day at 3:15 (am)
  paymentsQueue.add(paymentsData, { repeat: { cron: '15 3 * * *' } });

As a tip, check your expressions here to verify they are correct: cron expression generator

Pause / Resume

A queue can be paused and resumed globally (pass true to pause processing for just this worker):

queue.pause().then(function () {
  // queue is paused now
});

queue.resume().then(function () {
  // queue is resumed now
})

Events

A queue emits some useful events, for example...

.on('completed', function (job, result) {
  // Job completed with output result!
})

For more information on events, including the full list of events that are fired, check out the Events reference

Queues performance

Queues are cheap, so if you need many of them just create new ones with different names:

const userJohn = new Queue('john');
const userLisa = new Queue('lisa');
.
.
.

However every queue instance will require new redis connections, check how to reuse connections or you can also use named processors to achieve a similar result.

Cluster support

NOTE: From version 3.2.0 and above it is recommended to use threaded processors instead.

Queues are robust and can be run in parallel in several threads or processes without any risk of hazards or queue corruption. Check this simple example using cluster to parallelize jobs across processes:

const Queue = require('bull');
const cluster = require('cluster');

const numWorkers = 8;
const queue = new Queue('test concurrent queue');

if (cluster.isMaster) {
  for (let i = 0; i < numWorkers; i++) {
    cluster.fork();
  }

  cluster.on('online', function (worker) {
    // Let's create a few jobs for the queue workers
    for (let i = 0; i < 500; i++) {
      queue.add({ foo: 'bar' });
    };
  });

  cluster.on('exit', function (worker, code, signal) {
    console.log('worker ' + worker.process.pid + ' died');
  });
} else {
  queue.process(function (job, jobDone) {
    console.log('Job done by worker', cluster.worker.id, job.id);
    jobDone();
  });
}

Documentation

For the full documentation, check out the reference and common patterns:

  • Guide — Your starting point for developing with Bull.
  • Reference — Reference document with all objects and methods available.
  • Patterns — a set of examples for common patterns.
  • License — the Bull license—it's MIT.

If you see anything that could use more docs, please submit a pull request!


Important Notes

The queue aims for an "at least once" working strategy. This means that in some situations, a job could be processed more than once. This mostly happens when a worker fails to keep a lock for a given job during the total duration of the processing.

When a worker is processing a job it will keep the job "locked" so other workers can't process it.

It's important to understand how locking works to prevent your jobs from losing their lock - becoming stalled - and being restarted as a result. Locking is implemented internally by creating a lock for lockDuration on interval lockRenewTime (which is usually half lockDuration). If lockDuration elapses before the lock can be renewed, the job will be considered stalled and is automatically restarted; it will be double processed. This can happen when:

  1. The Node process running your job processor unexpectedly terminates.
  2. Your job processor was too CPU-intensive and stalled the Node event loop, and as a result, Bull couldn't renew the job lock (see #488 for how we might better detect this). You can fix this by breaking your job processor into smaller parts so that no single part can block the Node event loop. Alternatively, you can pass a larger value for the lockDuration setting (with the tradeoff being that it will take longer to recognize a real stalled job).

As such, you should always listen for the stalled event and log this to your error monitoring system, as this means your jobs are likely getting double-processed.

As a safeguard so problematic jobs won't get restarted indefinitely (e.g. if the job processor always crashes its Node process), jobs will be recovered from a stalled state a maximum of maxStalledCount times (default: 1).