UNPKG

18.4 kBMarkdownView Raw
1
2<div align="center">
3 <br/>
4 <img src="./support/logo@2x.png" width="300" />
5 <br/>
6 <br/>
7 <p>
8 The fastest, most reliable, Redis-based queue for Node. <br/>
9 Carefully written for rock solid stability and atomicity.
10 </p>
11 <br/>
12 <p>
13 <a href="#-sponsors-"><strong>Sponsors</strong></a> ·
14 <a href="#bull-features"><strong>Features</strong></a> ·
15 <a href="#uis"><strong>UIs</strong></a> ·
16 <a href="#install"><strong>Install</strong></a> ·
17 <a href="#quick-guide"><strong>Quick Guide</strong></a> ·
18 <a href="#documentation"><strong>Documentation</strong></a>
19 </p>
20 <p>Check the new <a href="https://optimalbits.github.io/bull/"><strong>Guide!</strong></p>
21 <br/>
22 <p>
23 <a href="https://gitter.im/OptimalBits/bull">
24 <img src="https://badges.gitter.im/Join%20Chat.svg"/>
25 </a>
26 <a href="https://gitter.im/OptimalBits/bull">
27 <img src="https://img.shields.io/npm/dm/bull.svg?maxAge=2592000"/>
28 </a>
29 <a href="http://badge.fury.io/js/bull">
30 <img src="https://badge.fury.io/js/bull.svg"/>
31 </a>
32 <a href="https://coveralls.io/github/OptimalBits/bull?branch=master">
33 <img src="https://coveralls.io/repos/github/OptimalBits/bull/badge.svg?branch=master"/>
34 </a>
35 <a href="http://isitmaintained.com/project/OptimalBits/bull">
36 <img src="http://isitmaintained.com/badge/open/optimalbits/bull.svg"/>
37 </a>
38 <a href="http://isitmaintained.com/project/OptimalBits/bull">
39 <img src="http://isitmaintained.com/badge/resolution/optimalbits/bull.svg"/>
40 </a>
41 <a href="https://twitter.com/manast">
42 <img src="https://img.shields.io/twitter/follow/manast?label=Stay%20updated&style=social"/>
43 </a>
44 </p>
45</div>
46
47### 📻 News and updates
48
49Bull is currently in maintenance mode, we are only fixing bugs. For new features check [BullMQ](https://github.com/taskforcesh/bullmq), a modern rewritten
50implementation in Typescript. You are still very welcome to use Bull if it suits your needs, which is a safe, battle tested library.
51
52Follow me on [Twitter](http://twitter.com/manast) for other important news and updates.
53
54### 🛠 Tutorials
55
56You can find tutorials and news in this blog: https://blog.taskforce.sh/
57
58---
59
60### Used by
61
62Bull is popular among large and small organizations, like the following ones:
63
64<table cellspacing="0" cellpadding="0">
65 <tr>
66 <td valign="center">
67 <a href="https://github.com/atlassian/github-for-jira">
68 <img
69 src="https://876297641-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LUuDmt_xXMfG66Rn1GA%2Fuploads%2FevsJCF6F1tx1ScZwDQOd%2FAtlassian-horizontal-blue-rgb.webp?alt=media&token=2fcd0528-e8bb-4bdd-af35-9d20e313d1a8"
70 width="150"
71 alt="Atlassian"
72 /></a>
73 </td>
74 <td valign="center">
75 <a href="https://github.com/Autodesk">
76 <img
77 src="https://876297641-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LUuDmt_xXMfG66Rn1GA%2Fuploads%2FvpTe02RdOhUJBA8TdHEE%2Fautodesk-logo-white.png?alt=media&token=326961b4-ea4f-4ded-89a4-e05692eec8ee"
78 width="150"
79 alt="Autodesk"
80 /></a>
81 </td>
82 <td valign="center">
83 <a href="https://github.com/common-voice/common-voice">
84 <img
85 src="https://876297641-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LUuDmt_xXMfG66Rn1GA%2Fuploads%2F4zPSrubNJKViAzUIftIy%2Fmozilla-logo-bw-rgb.png?alt=media&token=9f93aae2-833f-4cc4-8df9-b7fea0ad5cb5"
86 width="150"
87 alt="Mozilla"
88 /></a>
89 </td>
90 <td valign="center">
91 <a href="https://github.com/nestjs/bull">
92 <img
93 src="https://876297641-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LUuDmt_xXMfG66Rn1GA%2Fuploads%2FfAcGye182utFUtPKdLqJ%2FScreenshot%202022-02-15%20at%2011.32.39.png?alt=media&token=29feb550-f0bc-467d-a290-f700701d7d15"
94 width="150"
95 alt="Nest"
96 /></a>
97 </td>
98 <td valign="center">
99 <a href="https://github.com/salesforce/refocus">
100 <img
101 src="https://876297641-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LUuDmt_xXMfG66Rn1GA%2Fuploads%2FZNnYNuL5qJ6ZoBh7JJEW%2Fsalesforce-logo.png?alt=media&token=ddcae63b-08c0-4dd4-8496-3b29a9bf977d"
102 width="100"
103 alt="Salesforce"
104 /></a>
105 </td>
106
107 </tr>
108</table>
109
110---
111
112### 🚀 Sponsors 🚀
113
114[<img src="https://www.memetria.com/images/logo/memetria-logo.svg" width="300" alt="Memetria for Redis" style="padding: 100px"/>](https://dashboard.memetria.com/new?utm_campaign=BULLMQ)
115
116If you need high quality production Redis instances for your Bull projects, please consider subscribing
117to [Memetria for Redis](https://dashboard.memetria.com/new?utm_campaign=BULLMQ),
118leaders in Redis hosting that works perfectly with Bull. Use the promo code "BULLMQ" when signing up to help us
119sponsor the development of Bull!
120
121---
122
123### Official FrontEnd
124
125[<img src="http://taskforce.sh/assets/logo_square.png" width="100" alt="Taskforce.sh, Inc" style="padding: 100px"/>](https://taskforce.sh)
126
127Supercharge your queues with a professional front end:
128- Get a complete overview of all your queues.
129- Inspect jobs, search, retry, or promote delayed jobs.
130- Metrics and statistics.
131- and many more features.
132
133Sign up at [Taskforce.sh](https://taskforce.sh)
134
135---
136
137### Bull Features
138
139- [x] Minimal CPU usage due to a polling-free design.
140- [x] Robust design based on Redis.
141- [x] Delayed jobs.
142- [x] Schedule and repeat jobs according to a cron specification.
143- [x] Rate limiter for jobs.
144- [x] Retries.
145- [x] Priority.
146- [x] Concurrency.
147- [x] Pause/resume—globally or locally.
148- [x] Multiple job types per queue.
149- [x] Threaded (sandboxed) processing functions.
150- [x] Automatic recovery from process crashes.
151
152And coming up on the roadmap...
153
154- [ ] Job completion acknowledgement (you can use the message queue [pattern](https://github.com/OptimalBits/bull/blob/develop/PATTERNS.md#returning-job-completions) in the meantime).
155- [ ] Parent-child jobs relationships.
156
157---
158
159### UIs
160
161There are a few third-party UIs that you can use for monitoring:
162
163**BullMQ**
164
165- [Taskforce](https://taskforce.sh)
166
167**Bull v3**
168
169- [Taskforce](https://taskforce.sh)
170- [bull-board](https://github.com/vcapretz/bull-board)
171- [bull-repl](https://github.com/darky/bull-repl)
172- [bull-monitor](https://github.com/s-r-x/bull-monitor)
173- [Monitoro](https://github.com/AbhilashJN/monitoro)
174
175**Bull <= v2**
176
177- [Matador](https://github.com/ShaneK/Matador)
178- [react-bull](https://github.com/kfatehi/react-bull)
179- [Toureiro](https://github.com/Epharmix/Toureiro)
180
181---
182
183### Monitoring & Alerting
184
185- With Prometheus [Bull Queue Exporter](https://github.com/UpHabit/bull_exporter)
186
187---
188
189### Feature Comparison
190
191Since there are a few job queue solutions, here is a table comparing them:
192
193| Feature | Bullmq-Pro | Bullmq | Bull | Kue | Bee | Agenda |
194| :------------------------ | :-------------: | :-------------: | :-------------: | :---: | -------- | ------ |
195| Backend | redis | redis | redis | redis | redis | mongo |
196| Observables | ✓ | | | | | |
197| Group Rate Limit | ✓ | | | | | |
198| Group Support | ✓ | | | | | |
199| Parent/Child Dependencies | ✓ | ✓ | | | | |
200| Priorities | ✓ | ✓ | ✓ | ✓ | | ✓ |
201| Concurrency | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
202| Delayed jobs | ✓ | ✓ | ✓ | ✓ | | ✓ |
203| Global events | ✓ | ✓ | ✓ | ✓ | | |
204| Rate Limiter | ✓ | ✓ | ✓ | | | |
205| Pause/Resume | ✓ | ✓ | ✓ | ✓ | | |
206| Sandboxed worker | ✓ | ✓ | ✓ | | | |
207| Repeatable jobs | ✓ | ✓ | ✓ | | | ✓ |
208| Atomic ops | ✓ | ✓ | ✓ | | ✓ | |
209| Persistence | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
210| UI | ✓ | ✓ | ✓ | ✓ | | ✓ |
211| Optimized for | Jobs / Messages | Jobs / Messages | Jobs / Messages | Jobs | Messages | Jobs |
212
213
214### Install
215
216```bash
217npm install bull --save
218```
219or
220
221```bash
222yarn add bull
223```
224
225_**Requirements:** Bull requires a Redis version greater than or equal to `2.8.18`._
226
227
228### Typescript Definitions
229
230```bash
231npm install @types/bull --save-dev
232```
233```bash
234yarn add --dev @types/bull
235```
236
237Definitions are currently maintained in the [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/bull) repo.
238
239
240## Contributing
241
242We welcome all types of contributions, either code fixes, new features or doc improvements.
243Code formatting is enforced by [prettier](https://prettier.io/).
244For commits please follow conventional [commits convention](https://www.conventionalcommits.org/en/v1.0.0-beta.2/).
245All code must pass lint rules and test suites before it can be merged into develop.
246
247---
248
249### Quick Guide
250
251#### Basic Usage
252```js
253const Queue = require('bull');
254
255const videoQueue = new Queue('video transcoding', 'redis://127.0.0.1:6379');
256const audioQueue = new Queue('audio transcoding', { redis: { port: 6379, host: '127.0.0.1', password: 'foobared' } }); // Specify Redis connection using object
257const imageQueue = new Queue('image transcoding');
258const pdfQueue = new Queue('pdf transcoding');
259
260videoQueue.process(function (job, done) {
261
262 // job.data contains the custom data passed when the job was created
263 // job.id contains id of this job.
264
265 // transcode video asynchronously and report progress
266 job.progress(42);
267
268 // call done when finished
269 done();
270
271 // or give an error if error
272 done(new Error('error transcoding'));
273
274 // or pass it a result
275 done(null, { framerate: 29.5 /* etc... */ });
276
277 // If the job throws an unhandled exception it is also handled correctly
278 throw new Error('some unexpected error');
279});
280
281audioQueue.process(function (job, done) {
282 // transcode audio asynchronously and report progress
283 job.progress(42);
284
285 // call done when finished
286 done();
287
288 // or give an error if error
289 done(new Error('error transcoding'));
290
291 // or pass it a result
292 done(null, { samplerate: 48000 /* etc... */ });
293
294 // If the job throws an unhandled exception it is also handled correctly
295 throw new Error('some unexpected error');
296});
297
298imageQueue.process(function (job, done) {
299 // transcode image asynchronously and report progress
300 job.progress(42);
301
302 // call done when finished
303 done();
304
305 // or give an error if error
306 done(new Error('error transcoding'));
307
308 // or pass it a result
309 done(null, { width: 1280, height: 720 /* etc... */ });
310
311 // If the job throws an unhandled exception it is also handled correctly
312 throw new Error('some unexpected error');
313});
314
315pdfQueue.process(function (job) {
316 // Processors can also return promises instead of using the done callback
317 return pdfAsyncProcessor();
318});
319
320videoQueue.add({ video: 'http://example.com/video1.mov' });
321audioQueue.add({ audio: 'http://example.com/audio1.mp3' });
322imageQueue.add({ image: 'http://example.com/image1.tiff' });
323```
324
325#### Using promises
326
327Alternatively, you can use return promises instead of using the `done` callback:
328
329```javascript
330videoQueue.process(function (job) { // don't forget to remove the done callback!
331 // Simply return a promise
332 return fetchVideo(job.data.url).then(transcodeVideo);
333
334 // Handles promise rejection
335 return Promise.reject(new Error('error transcoding'));
336
337 // Passes the value the promise is resolved with to the "completed" event
338 return Promise.resolve({ framerate: 29.5 /* etc... */ });
339
340 // If the job throws an unhandled exception it is also handled correctly
341 throw new Error('some unexpected error');
342 // same as
343 return Promise.reject(new Error('some unexpected error'));
344});
345```
346
347#### Separate processes
348
349The process function can also be run in a separate process. This has several advantages:
350- The process is sandboxed so if it crashes it does not affect the worker.
351- You can run blocking code without affecting the queue (jobs will not stall).
352- Much better utilization of multi-core CPUs.
353- Less connections to redis.
354
355In order to use this feature just create a separate file with the processor:
356```js
357// processor.js
358module.exports = function (job) {
359 // Do some heavy work
360
361 return Promise.resolve(result);
362}
363```
364
365And define the processor like this:
366
367```js
368// Single process:
369queue.process('/path/to/my/processor.js');
370
371// You can use concurrency as well:
372queue.process(5, '/path/to/my/processor.js');
373
374// and named processors:
375queue.process('my processor', 5, '/path/to/my/processor.js');
376```
377
378#### Repeated jobs
379
380A job can be added to a queue and processed repeatedly according to a cron specification:
381
382```js
383 paymentsQueue.process(function (job) {
384 // Check payments
385 });
386
387 // Repeat payment job once every day at 3:15 (am)
388 paymentsQueue.add(paymentsData, { repeat: { cron: '15 3 * * *' } });
389
390```
391
392As a tip, check your expressions here to verify they are correct:
393[cron expression generator](https://crontab.cronhub.io)
394
395#### Pause / Resume
396
397A queue can be paused and resumed globally (pass `true` to pause processing for
398just this worker):
399```js
400queue.pause().then(function () {
401 // queue is paused now
402});
403
404queue.resume().then(function () {
405 // queue is resumed now
406})
407```
408
409#### Events
410
411A queue emits some useful events, for example...
412```js
413.on('completed', function (job, result) {
414 // Job completed with output result!
415})
416```
417
418For more information on events, including the full list of events that are fired, check out the [Events reference](./REFERENCE.md#events)
419
420#### Queues performance
421
422Queues are cheap, so if you need many of them just create new ones with different
423names:
424```javascript
425const userJohn = new Queue('john');
426const userLisa = new Queue('lisa');
427.
428.
429.
430```
431
432However every queue instance will require new redis connections, check how to [reuse connections](https://github.com/OptimalBits/bull/blob/master/PATTERNS.md#reusing-redis-connections) or you can also use [named processors](https://github.com/OptimalBits/bull/blob/master/REFERENCE.md#queueprocess) to achieve a similar result.
433
434#### Cluster support
435
436NOTE: From version 3.2.0 and above it is recommended to use threaded processors instead.
437
438Queues are robust and can be run in parallel in several threads or processes
439without any risk of hazards or queue corruption. Check this simple example
440using cluster to parallelize jobs across processes:
441```js
442const Queue = require('bull');
443const cluster = require('cluster');
444
445const numWorkers = 8;
446const queue = new Queue('test concurrent queue');
447
448if (cluster.isMaster) {
449 for (let i = 0; i < numWorkers; i++) {
450 cluster.fork();
451 }
452
453 cluster.on('online', function (worker) {
454 // Let's create a few jobs for the queue workers
455 for (let i = 0; i < 500; i++) {
456 queue.add({ foo: 'bar' });
457 };
458 });
459
460 cluster.on('exit', function (worker, code, signal) {
461 console.log('worker ' + worker.process.pid + ' died');
462 });
463} else {
464 queue.process(function (job, jobDone) {
465 console.log('Job done by worker', cluster.worker.id, job.id);
466 jobDone();
467 });
468}
469```
470
471---
472
473
474### Documentation
475
476For the full documentation, check out the reference and common patterns:
477
478- [Guide](https://optimalbits.github.io/bull/) — Your starting point for developing with Bull.
479- [Reference](./REFERENCE.md) — Reference document with all objects and methods available.
480- [Patterns](./PATTERNS.md) — a set of examples for common patterns.
481- [License](./LICENSE.md) — the Bull license—it's MIT.
482
483If you see anything that could use more docs, please submit a pull request!
484
485
486
487---
488
489### Important Notes
490
491The queue aims for an "at least once" working strategy. This means that in some situations, a job
492could be processed more than once. This mostly happens when a worker fails to keep a lock
493for a given job during the total duration of the processing.
494
495When a worker is processing a job it will keep the job "locked" so other workers can't process it.
496
497It's important to understand how locking works to prevent your jobs from losing their lock - becoming _stalled_ -
498and being restarted as a result. Locking is implemented internally by creating a lock for `lockDuration` on interval
499`lockRenewTime` (which is usually half `lockDuration`). If `lockDuration` elapses before the lock can be renewed,
500the job will be considered stalled and is automatically restarted; it will be __double processed__. This can happen when:
5011. The Node process running your job processor unexpectedly terminates.
5022. 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](https://github.com/OptimalBits/bull/issues/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).
503
504As 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.
505
506As 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`).