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