bull vs agenda vs bee-queue vs bree vs kue vs node-resque
노드.js 작업 큐 라이브러리
bullagendabee-queuebreekuenode-resqueÄhnliche Pakete:

노드.js 작업 큐 라이브러리

노드.js 작업 큐 라이브러리는 비동기 작업을 관리하고 처리하기 위한 도구입니다. 이 라이브러리들은 백그라운드에서 작업을 실행하고, 작업의 우선순위를 설정하며, 실패한 작업을 재시도하는 등의 기능을 제공합니다. 이를 통해 웹 애플리케이션의 성능을 향상시키고, 사용자 경험을 개선할 수 있습니다.

npm-Download-Trend

3 Jahre

GitHub Stars Ranking

Statistik-Detail

Paket
Downloads
Stars
Größe
Issues
Veröffentlichung
Lizenz
bull2,245,94716,262309 kB147vor 2 JahrenMIT
agenda228,6899,712310 kB19vor 10 StundenMIT
bee-queue67,7854,039107 kB46vor einem JahrMIT
bree42,9493,29692 kB30vor 8 MonatenMIT
kue31,0799,418-286vor 9 JahrenMIT
node-resque26,4421,415720 kB24vor 3 MonatenApache-2.0

Funktionsvergleich: bull vs agenda vs bee-queue vs bree vs kue vs node-resque

데이터 저장소 지원

  • bull:

    Bull은 Redis를 사용하여 작업을 저장하고, 다양한 기능을 통해 작업의 상태를 관리합니다.

  • agenda:

    Agenda는 MongoDB를 사용하여 작업을 저장하고 관리합니다. MongoDB의 강력한 쿼리 기능을 활용할 수 있어 복잡한 작업 스케줄링에 유리합니다.

  • bee-queue:

    Bee-Queue는 Redis를 사용하여 작업을 저장합니다. Redis의 빠른 성능 덕분에 높은 처리량을 자랑합니다.

  • bree:

    Bree는 파일 기반의 작업 스케줄링을 지원하며, 별도의 데이터 저장소 없이도 작업을 관리할 수 있습니다.

  • kue:

    Kue는 Redis를 기반으로 하며, 작업의 상태를 쉽게 추적할 수 있는 대시보드를 제공합니다.

  • node-resque:

    Node-resque는 Redis를 사용하여 작업을 관리하며, 다양한 큐와 작업 처리 방식을 지원합니다.

성능

  • bull:

    Bull은 Redis의 성능을 활용하여 대량의 작업을 효율적으로 처리할 수 있습니다. 다양한 기능을 통해 성능을 최적화할 수 있습니다.

  • agenda:

    Agenda는 MongoDB의 성능에 의존하므로, 데이터베이스의 성능이 작업 처리 속도에 영향을 미칠 수 있습니다. 대량의 작업을 처리할 때 성능 저하가 발생할 수 있습니다.

  • bee-queue:

    Bee-Queue는 Redis의 성능을 극대화하여 높은 처리량을 자랑합니다. 경량화된 구조 덕분에 빠른 작업 처리가 가능합니다.

  • bree:

    Bree는 Node.js의 기본 기능을 활용하여 경량화된 작업 스케줄링을 제공하므로, 성능이 우수합니다.

  • kue:

    Kue는 Redis를 기반으로 하여 성능이 우수하지만, 대량의 작업을 처리할 때 성능 저하가 발생할 수 있습니다.

  • node-resque:

    Node-resque는 Redis의 성능을 활용하여 작업을 처리하므로, 높은 성능을 유지합니다.

사용 용이성

  • bull:

    Bull은 다양한 기능을 제공하지만, 설정이 다소 복잡할 수 있습니다. 그러나 문서가 잘 정리되어 있어 이해하기 쉽습니다.

  • agenda:

    Agenda는 MongoDB와의 통합이 필요하므로, 설정이 다소 복잡할 수 있습니다. 그러나 API가 직관적이어서 사용하기 쉽습니다.

  • bee-queue:

    Bee-Queue는 간단한 API를 제공하여 사용이 용이합니다. 빠르게 시작할 수 있는 장점이 있습니다.

  • bree:

    Bree는 설정이 간단하고, Node.js의 기본 기능을 활용하여 쉽게 사용할 수 있습니다.

  • kue:

    Kue는 웹 기반 대시보드를 제공하여 작업 상태를 쉽게 모니터링할 수 있습니다. 그러나 설정이 복잡할 수 있습니다.

  • node-resque:

    Node-resque는 다양한 플러그인 시스템을 제공하여 유연한 사용이 가능합니다. 그러나 초기 설정이 다소 복잡할 수 있습니다.

작업 모니터링

  • bull:

    Bull은 웹 기반 대시보드를 제공하여 작업 상태를 시각적으로 모니터링할 수 있습니다. 작업의 성공 및 실패 상태를 쉽게 확인할 수 있습니다.

  • agenda:

    Agenda는 기본적인 작업 모니터링 기능을 제공하지만, 별도의 대시보드는 없습니다. MongoDB의 쿼리를 통해 작업 상태를 확인할 수 있습니다.

  • bee-queue:

    Bee-Queue는 작업 상태를 실시간으로 모니터링할 수 있는 기능을 제공합니다. 간단한 API로 작업 상태를 확인할 수 있습니다.

  • bree:

    Bree는 기본적인 작업 모니터링 기능을 제공하지만, 별도의 대시보드는 없습니다.

  • kue:

    Kue는 강력한 대시보드를 제공하여 작업 상태를 시각적으로 모니터링할 수 있습니다. 작업의 진행 상황을 쉽게 추적할 수 있습니다.

  • node-resque:

    Node-resque는 작업 상태를 모니터링할 수 있는 기능을 제공하지만, 별도의 대시보드는 없습니다.

재시도 기능

  • bull:

    Bull은 작업 실패 시 재시도 기능을 제공하여, 실패한 작업을 자동으로 재처리할 수 있습니다.

  • agenda:

    Agenda는 작업 실패 시 재시도 기능을 기본적으로 제공하지 않습니다. 사용자 정의 로직을 구현해야 합니다.

  • bee-queue:

    Bee-Queue는 작업 실패 시 재시도 기능을 제공하여, 실패한 작업을 자동으로 재처리할 수 있습니다.

  • bree:

    Bree는 작업 실패 시 재시도 기능을 제공하지 않습니다. 사용자 정의 로직을 구현해야 합니다.

  • kue:

    Kue는 작업 실패 시 재시도 기능을 제공하여, 실패한 작업을 자동으로 재처리할 수 있습니다.

  • node-resque:

    Node-resque는 작업 실패 시 재시도 기능을 제공하여, 실패한 작업을 자동으로 재처리할 수 있습니다.

Wie man wählt: bull vs agenda vs bee-queue vs bree vs kue vs node-resque

  • bull:

    Bull은 Redis 기반의 강력한 작업 큐로, 다양한 기능과 우선순위 처리, 지연 작업 등을 지원합니다. 복잡한 작업 흐름을 관리해야 할 때 적합합니다.

  • agenda:

    Agenda는 MongoDB를 기반으로 한 작업 스케줄링 라이브러리로, 주기적인 작업이 필요한 경우에 적합합니다. MongoDB와의 통합이 필요하고, 복잡한 작업 스케줄링이 요구되는 경우 선택하세요.

  • bee-queue:

    Bee-Queue는 Redis를 사용하는 경량 작업 큐로, 높은 성능과 간단한 API를 제공합니다. 빠른 작업 처리가 필요한 경우에 적합하며, 간단한 설정으로 시작할 수 있습니다.

  • bree:

    Bree는 Node.js의 기본 기능을 활용하여 작업을 스케줄링하는 라이브러리로, 경량화된 작업 스케줄링이 필요할 때 유용합니다. 복잡한 설정 없이 쉽게 사용할 수 있습니다.

  • kue:

    Kue는 Redis를 기반으로 한 작업 큐로, 웹 기반 대시보드를 제공하여 작업 상태를 모니터링할 수 있습니다. 작업의 시각화가 필요할 때 유용합니다.

  • node-resque:

    Node-resque는 Resque의 Node.js 구현으로, Redis를 사용하여 작업 큐를 관리합니다. 다양한 작업 처리 방식과 플러그인 시스템을 제공하여 유연한 작업 처리가 가능합니다.

README für 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

  • Minimal CPU usage due to a polling-free design.
  • Robust design based on Redis.
  • Delayed jobs.
  • Schedule and repeat jobs according to a cron specification.
  • Rate limiter for jobs.
  • Retries.
  • Priority.
  • Concurrency.
  • Pause/resume—globally or locally.
  • Multiple job types per queue.
  • Threaded (sandboxed) processing functions.
  • 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:

FeatureBullMQ-ProBullMQBullKueBeeAgenda
Backendredisredisredisredisredismongo
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 forJobs / MessagesJobs / MessagesJobs / MessagesJobsMessagesJobs

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).