Full Code of OptimalBits/bull for AI

develop 03c546729d4d cached
108 files
573.0 KB
151.6k tokens
152 symbols
1 requests
Download .txt
Showing preview only (604K chars total). Download the full file or copy to clipboard to get everything.
Repository: OptimalBits/bull
Branch: develop
Commit: 03c546729d4d
Files: 108
Total size: 573.0 KB

Directory structure:
gitextract_f80qykri/

├── .editorconfig
├── .eslintrc.yml
├── .github/
│   ├── issue_template.md
│   ├── stale.yml
│   └── workflows/
│       ├── codeql-analysis.yml
│       ├── node.js.yml
│       └── release.yml
├── .gitignore
├── .mocharc.json
├── .npmignore
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE.md
├── MIGRATION.md
├── PATTERNS.md
├── README.md
├── REFERENCE.md
├── commandTransform.js
├── commitlint.config.js
├── docker-compose.yml
├── docs/
│   ├── README.md
│   └── _config.yml
├── generateRawScripts.js
├── index.d.ts
├── index.js
├── lib/
│   ├── backoffs.js
│   ├── commands/
│   │   ├── addJob-6.lua
│   │   ├── addLog-2.lua
│   │   ├── cleanJobsInSet-3.lua
│   │   ├── extendLock-2.lua
│   │   ├── getCountsPerPriority-4.lua
│   │   ├── includes/
│   │   │   ├── addJobWithPriority.lua
│   │   │   ├── batches.lua
│   │   │   ├── collectMetrics.lua
│   │   │   ├── debounceJob.lua
│   │   │   ├── getTargetQueueList.lua
│   │   │   ├── removeDebounceKey.lua
│   │   │   ├── removeDebounceKeyIfNeeded.lua
│   │   │   └── removeLock.lua
│   │   ├── index.js
│   │   ├── isFinished-2.lua
│   │   ├── isJobInList-1.lua
│   │   ├── moveStalledJobsToWait-7.lua
│   │   ├── moveToActive-8.lua
│   │   ├── moveToDelayed-4.lua
│   │   ├── moveToFinished-9.lua
│   │   ├── obliterate-2.lua
│   │   ├── pause-5.lua
│   │   ├── promote-5.lua
│   │   ├── releaseLock-1.lua
│   │   ├── removeJob-11.lua
│   │   ├── removeJobs-8.lua
│   │   ├── removeRepeatable-2.lua
│   │   ├── reprocessJob-6.lua
│   │   ├── retryJob-7.lua
│   │   ├── retryJobs-5.lua
│   │   ├── saveStacktrace-1.lua
│   │   ├── script-loader.js
│   │   ├── takeLock-1.lua
│   │   ├── updateData-1.lua
│   │   ├── updateDelaySet-6.lua
│   │   └── updateProgress-2.lua
│   ├── errors.js
│   ├── getters.js
│   ├── job.js
│   ├── p-timeout.js
│   ├── process/
│   │   ├── child-pool.js
│   │   ├── master.js
│   │   ├── sandbox.js
│   │   └── utils.js
│   ├── queue.js
│   ├── repeatable.js
│   ├── scripts.js
│   ├── timer-manager.js
│   ├── utils.js
│   └── worker.js
├── package.json
├── support/
│   └── logo.sketch
└── test/
    ├── .eslintrc.yml
    ├── fixtures/
    │   ├── fixture_processor.js
    │   ├── fixture_processor_bar.js
    │   ├── fixture_processor_broken.js
    │   ├── fixture_processor_callback.js
    │   ├── fixture_processor_callback_fail.js
    │   ├── fixture_processor_crash.js
    │   ├── fixture_processor_data.js
    │   ├── fixture_processor_discard.js
    │   ├── fixture_processor_exit.js
    │   ├── fixture_processor_fail.js
    │   ├── fixture_processor_foo.js
    │   ├── fixture_processor_progress.js
    │   └── fixture_processor_slow.js
    ├── test_child-pool.js
    ├── test_connection.js
    ├── test_events.js
    ├── test_getters.js
    ├── test_job.js
    ├── test_metrics.js
    ├── test_obliterate.js
    ├── test_pause.js
    ├── test_queue.js
    ├── test_rate_limiter.js
    ├── test_repeat.js
    ├── test_sandboxed_process.js
    ├── test_when_current_jobs_finished.js
    ├── test_worker.js
    └── utils.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
; EditorConfig file: http://EditorConfig.org
; Install the "EditorConfig" plugin into Sublime Text to use

root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true


================================================
FILE: .eslintrc.yml
================================================
env:
  node: true

parserOptions:
  ecmaVersion: 2018

extends:
  - eslint:recommended
  - plugin:mocha/recommended
  - plugin:node/recommended

plugins:
  - mocha
  - node

rules:
  valid-jsdoc: 0
  func-style: 0
  no-use-before-define: 0
  camelcase: 1
  no-unused-vars: 2
  no-alert: 2
  no-console: [2, { allow: ['warn', 'error'] }]
  no-underscore-dangle: 0
  object-shorthand: 0

  strict: [2, 'global']
  no-var: 2
  prefer-arrow-callback: 2
  prefer-const: 2
  no-inner-declarations: 0
  newline-per-chained-call: 2

  mocha/no-exclusive-tests: 2
  mocha/no-hooks-for-single-case: 0
  mocha/no-mocha-arrows: 0
  mocha/no-setup-in-describe: 0
  mocha/no-sibling-hooks: 0
  mocha/no-skipped-tests: 0

  node/no-deprecated-api: 0


================================================
FILE: .github/issue_template.md
================================================
<!--
You may report several types of issues. Bug reports, enhancements or questions.
For bug reports however you are required to provide some information so that the 
issue can be resolved efficiently. The following template should be filled for bugs.

Before submitting the bug just think twice if you really need to submit the bug
or you may have some issue in your own code, remember that handling issues is
time consuming, would you better like that we spend time improving the library
or on non-issues :).
-->

## Description

## Minimal, Working Test code to reproduce the issue.
#### (An easy to reproduce test case will dramatically decrease the resolution time.)

## Bull version

## Additional information



================================================
FILE: .github/stale.yml
================================================
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
  - pinned
  - security
  - enhancement
  - BETTER DOC
  - bug
# Label to use when marking an issue as stale
staleLabel: wontfix
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
  This issue has been automatically marked as stale because it has not had
  recent activity. It will be closed if no further activity occurs. Thank you
  for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false


================================================
FILE: .github/workflows/codeql-analysis.yml
================================================
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"

on:
  push:
    branches: [ develop ]
  pull_request:
    # The branches below must be a subset of the branches above
    branches: [ develop ]
  schedule:
    - cron: '24 2 * * 0'

jobs:
  analyze:
    name: Analyze
    runs-on: ubuntu-latest
    permissions:
      actions: read
      contents: read
      security-events: write

    strategy:
      fail-fast: false
      matrix:
        language: [ 'javascript' ]
        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
        # Learn more about CodeQL language support at https://git.io/codeql-language-support

    steps:
    - name: Checkout repository
      uses: actions/checkout@v2

    # Initializes the CodeQL tools for scanning.
    - name: Initialize CodeQL
      uses: github/codeql-action/init@v1
      with:
        languages: ${{ matrix.language }}
        # If you wish to specify custom queries, you can do so here or in a config file.
        # By default, queries listed here will override any specified in a config file.
        # Prefix the list here with "+" to use these queries and those in the config file.
        # queries: ./path/to/local/query, your-org/your-repo/queries@main

    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
    # If this step fails, then you should remove it and run the build manually (see below)
    - name: Autobuild
      uses: github/codeql-action/autobuild@v1

    # ℹ️ Command-line programs to run using the OS shell.
    # 📚 https://git.io/JvXDl

    # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
    #    and modify them (or add more) to build your code if your project
    #    uses a compiled language

    #- run: |
    #   make bootstrap
    #   make release

    - name: Perform CodeQL Analysis
      uses: github/codeql-action/analyze@v1


================================================
FILE: .github/workflows/node.js.yml
================================================
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions

name: Node.js CI

on:
  push:
    branches: [develop]
  pull_request:
    branches: [develop]

permissions:
  contents: read # to fetch code (actions/checkout)

jobs:
  build:
    runs-on: ubuntu-latest

    services:
      redis:
        image: redis
        ports:
          - 6379:6379

    strategy:
      matrix:
        node-version: [12.x, 14.x, 16.x]
        redis-version: [7.0-alpine]
        include:
          - node-version: '16.x'
            redis-version: 6-alpine

    steps:
      - uses: actions/checkout@v2
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v1
        with:
          node-version: ${{ matrix.node-version }}
      - run: yarn install --frozen-lockfile --non-interactive
      - run: yarn prettier -- --list-different
      - run: yarn test


================================================
FILE: .github/workflows/release.yml
================================================
name: Release
on:
  push:
    branches:
      - develop
permissions: {}
jobs:
  release:
    permissions:
      contents: write # for release publishing

    name: Release
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
        with:
          fetch-depth: 0
      - name: Setup Node.js
        uses: actions/setup-node@v1
        with:
          node-version: 12
      - name: Install dependencies
        run: yarn install --frozen-lockfile --non-interactive
      - name: Generate scripts
        run: yarn pretest
      - name: Release
        env:
          GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
        run: npx semantic-release


================================================
FILE: .gitignore
================================================
node_modules
tmp
coverage
*.rdb
.vscode
package-lock.json
.nyc_output
rawScripts
lib/scripts


================================================
FILE: .mocharc.json
================================================
{
  "timeout": 5000,
  "reporter": "spec",
  "exit": true
}


================================================
FILE: .npmignore
================================================
node_modules
tmp
test
bugs
docs
support
.github
.editorconfig
.eslintrc.yml
.travis.yml
.gitignore
*.md
commitlint.config.js
rawScripts
commandTransform.js
docker-compose.yml
generateRawScripts.js
.nyc_output
.mocharc.json
lib/commands/*.js


================================================
FILE: CHANGELOG.md
================================================
## [4.16.5](https://github.com/OptimalBits/bull/compare/v4.16.4...v4.16.5) (2024-12-18)


### Bug Fixes

* upgrade cron-parser dependency for Luxon CVE-2023-22467 ([e45698e](https://github.com/OptimalBits/bull/commit/e45698eb91b91a4676f9bafdb7bdb35043d2316d))

## [4.16.4](https://github.com/OptimalBits/bull/compare/v4.16.3...v4.16.4) (2024-11-01)


### Bug Fixes

* **deps:** bump msgpackr to 1.1.2 to resolve ERR_BUFFER_OUT_OF_BOUNDS error ([#2783](https://github.com/OptimalBits/bull/issues/2783)) fixes [#2782](https://github.com/OptimalBits/bull/issues/2782) ([bc0ae0a](https://github.com/OptimalBits/bull/commit/bc0ae0ae5b7fb2b067de94c3e51ce1bdd609806d))

## [4.16.3](https://github.com/OptimalBits/bull/compare/v4.16.2...v4.16.3) (2024-09-10)


### Bug Fixes

* **metrics:** differentiate points in different minutes to be more accurate ([#2770](https://github.com/OptimalBits/bull/issues/2770)) ([fbf2fa3](https://github.com/OptimalBits/bull/commit/fbf2fa397c865e6620aac39b291704e486f424d2))

## [4.16.2](https://github.com/OptimalBits/bull/compare/v4.16.1...v4.16.2) (2024-09-05)


### Performance Improvements

* **metrics:** save zeros as much as max data points ([#2767](https://github.com/OptimalBits/bull/issues/2767)) ([3a09840](https://github.com/OptimalBits/bull/commit/3a098406a86573150ad13d1487d16211030c4200))

## [4.16.1](https://github.com/OptimalBits/bull/compare/v4.16.0...v4.16.1) (2024-08-28)


### Bug Fixes

* **metrics:** use batches include when collecting metrics ([#2765](https://github.com/OptimalBits/bull/issues/2765)) fixes [#2764](https://github.com/OptimalBits/bull/issues/2764) [#2763](https://github.com/OptimalBits/bull/issues/2763) ([8276f72](https://github.com/OptimalBits/bull/commit/8276f72b30a7abc2f3fb5509f980d931027d0f0c))

# [4.16.0](https://github.com/OptimalBits/bull/compare/v4.15.1...v4.16.0) (2024-07-30)


### Features

* **job:** support debouncing ([#2760](https://github.com/OptimalBits/bull/issues/2760)) ([603befe](https://github.com/OptimalBits/bull/commit/603befe439fb4e318137b88550ab4d0c6c2bbcb3))

## [4.15.1](https://github.com/OptimalBits/bull/compare/v4.15.0...v4.15.1) (2024-07-04)


### Bug Fixes

* **job:** check jobKey when saving stacktrace ([#2755](https://github.com/OptimalBits/bull/issues/2755)) ([96675f5](https://github.com/OptimalBits/bull/commit/96675f51d1a9e5a30df0a0fe24a40a2d14078203))

# [4.15.0](https://github.com/OptimalBits/bull/compare/v4.14.0...v4.15.0) (2024-06-30)


### Features

* **queue:** emit internal duplicated event ([#2754](https://github.com/OptimalBits/bull/issues/2754)) ([021ab7f](https://github.com/OptimalBits/bull/commit/021ab7fd8d6c89b01767572b0e53422f34f7bc04))

# [4.14.0](https://github.com/OptimalBits/bull/compare/v4.13.1...v4.14.0) (2024-06-25)


### Features

* **queue:** add global:duplicated event when a duplicated is added ([#2749](https://github.com/OptimalBits/bull/issues/2749)) ([d632ac1](https://github.com/OptimalBits/bull/commit/d632ac1010d7d7faaa8f731eafdea67d6129e111))

## [4.13.1](https://github.com/OptimalBits/bull/compare/v4.13.0...v4.13.1) (2024-06-21)


### Bug Fixes

* **priority:** consider paused state when calling getCountsPerPriority ([#2748](https://github.com/OptimalBits/bull/issues/2748)) ([6c2719a](https://github.com/OptimalBits/bull/commit/6c2719a9292bf0a11136d575d333600be0b9a422))

# [4.13.0](https://github.com/OptimalBits/bull/compare/v4.12.9...v4.13.0) (2024-06-12)


### Features

* **queue:** add getCountsPerPriority method ([#2746](https://github.com/OptimalBits/bull/issues/2746)) ([0376dcc](https://github.com/OptimalBits/bull/commit/0376dcc128d9af13ecbd658d8ea7ff19fce56915))

## [4.12.9](https://github.com/OptimalBits/bull/compare/v4.12.8...v4.12.9) (2024-05-24)


### Bug Fixes

* **retry-job:** throw error when job is not in active state ([#2741](https://github.com/OptimalBits/bull/issues/2741)) ([c29e3b0](https://github.com/OptimalBits/bull/commit/c29e3b061a168c3d40a336a733c382bab14caa57))

## [4.12.8](https://github.com/OptimalBits/bull/compare/v4.12.7...v4.12.8) (2024-05-22)


### Bug Fixes

* **move-to-finished:** throw error when job is not in active state ([#2739](https://github.com/OptimalBits/bull/issues/2739)) ([7b12be1](https://github.com/OptimalBits/bull/commit/7b12be13ea39e309d6a6a39a2e56f646f06fdfa8))

## [4.12.7](https://github.com/OptimalBits/bull/compare/v4.12.6...v4.12.7) (2024-05-21)


### Bug Fixes

* **scripts:** throw error when moving non-active job to delayed ([#2740](https://github.com/OptimalBits/bull/issues/2740)) ([63636b1](https://github.com/OptimalBits/bull/commit/63636b181d0a166b1702059e5abb53ce1589d90f))

## [4.12.6](https://github.com/OptimalBits/bull/compare/v4.12.5...v4.12.6) (2024-05-18)


### Bug Fixes

* **stalled:** take in count removeOnFail option ([#2734](https://github.com/OptimalBits/bull/issues/2734)) ([2112269](https://github.com/OptimalBits/bull/commit/21122697461b551055192ff3b9c02c6f37cb331e))

## [4.12.5](https://github.com/OptimalBits/bull/compare/v4.12.4...v4.12.5) (2024-05-17)


### Bug Fixes

* **job:** validate job existence when adding log ([#2738](https://github.com/OptimalBits/bull/issues/2738)) ([1fb1562](https://github.com/OptimalBits/bull/commit/1fb15628dc5912e83220d430aa14e19e90d1cc53))

## [4.12.4](https://github.com/OptimalBits/bull/compare/v4.12.3...v4.12.4) (2024-05-15)


### Bug Fixes

* **retry-job:** consider priority ([#2737](https://github.com/OptimalBits/bull/issues/2737)) fixes [#1755](https://github.com/OptimalBits/bull/issues/1755) ([09ce146](https://github.com/OptimalBits/bull/commit/09ce146563871519cda638bafa82ce6af34bdd25))

## [4.12.3](https://github.com/OptimalBits/bull/compare/v4.12.2...v4.12.3) (2024-05-10)


### Bug Fixes

* **job:** validate jobKey in updateProgress and update ([#2730](https://github.com/OptimalBits/bull/issues/2730)) ([6d84156](https://github.com/OptimalBits/bull/commit/6d8415696606d3b7ec891f7fca9ab0508923c321))


### Performance Improvements

* **scripts:** remove token after moving to wait or delayed ([#2731](https://github.com/OptimalBits/bull/issues/2731)) ([7ee8f74](https://github.com/OptimalBits/bull/commit/7ee8f7430a68492c9ce768e7108443592f49d74c))

## [4.12.2](https://github.com/OptimalBits/bull/compare/v4.12.1...v4.12.2) (2024-01-17)


### Bug Fixes

* **dependencies:** upgrade msgpackr ([cc83ae2](https://github.com/OptimalBits/bull/commit/cc83ae297e96344f94039401be5097d7f05ab10b))

## [4.12.1](https://github.com/OptimalBits/bull/compare/v4.12.0...v4.12.1) (2024-01-15)


### Bug Fixes

* **deps:** bump msgpackr from 1.5.2 to 1.10.1 ([#2697](https://github.com/OptimalBits/bull/issues/2697)) ([b27c90d](https://github.com/OptimalBits/bull/commit/b27c90d8b106cc5319e712df2386ddc35946ec3d))

# [4.12.0](https://github.com/OptimalBits/bull/compare/v4.11.5...v4.12.0) (2023-12-18)


### Features

* add missing extendLock definition ([14432ff](https://github.com/OptimalBits/bull/commit/14432ff8a5e743d97c82a360c9d6a92204b1a684))

## [4.11.5](https://github.com/OptimalBits/bull/compare/v4.11.4...v4.11.5) (2023-11-11)


### Bug Fixes

* pass redis string as opts into queue ([e94f568](https://github.com/OptimalBits/bull/commit/e94f568085de079fc42b876233a060ba11ec946e))

## [4.11.4](https://github.com/OptimalBits/bull/compare/v4.11.3...v4.11.4) (2023-10-14)


### Bug Fixes

* catch pause errors when closing ([ccb6cc7](https://github.com/OptimalBits/bull/commit/ccb6cc7ecca8c726fc14509536831f665ac49701))

## [4.11.3](https://github.com/OptimalBits/bull/compare/v4.11.2...v4.11.3) (2023-08-11)


### Bug Fixes

* **types:** make repeat option key optional ([934ec98](https://github.com/OptimalBits/bull/commit/934ec9875c6e04c3e771b6c6ba212e3693d3a25b))

## [4.11.2](https://github.com/OptimalBits/bull/compare/v4.11.1...v4.11.2) (2023-08-08)


### Bug Fixes

* **worker:** better client name support ([5910f44](https://github.com/OptimalBits/bull/commit/5910f44b03a264d979c8ade54d64d13fdc908b51))

## [4.11.1](https://github.com/OptimalBits/bull/compare/v4.11.0...v4.11.1) (2023-08-08)


### Bug Fixes

* **queue:** deep clone opts ([#2634](https://github.com/OptimalBits/bull/issues/2634)) fixes [#2633](https://github.com/OptimalBits/bull/issues/2633) ([35f1da3](https://github.com/OptimalBits/bull/commit/35f1da3cf631bee97e96a774d9f1127466e7a66a))

# [4.11.0](https://github.com/OptimalBits/bull/compare/v4.10.4...v4.11.0) (2023-08-08)


### Bug Fixes

* add mising getMetrics type ([#2640](https://github.com/OptimalBits/bull/issues/2640)) ([a217a7d](https://github.com/OptimalBits/bull/commit/a217a7d56d52385eb56ffe386b7503eca9a24604))
* remove deprecated debuglog ([4ce36fe](https://github.com/OptimalBits/bull/commit/4ce36febe3a63a45198e2fe24b46fc371ee3f6e5))
* **types:** add missing keys to repeat opts ([e4e6457](https://github.com/OptimalBits/bull/commit/e4e64572a3ad259d9cb90d5dec81e8565eeadca1))
* **types:** rename strategyOptions to options to reflect js file ([bae6427](https://github.com/OptimalBits/bull/commit/bae6427ce9d9fac26b198402068bd84647fd8208))
* **typings:** return type of getJobCountByTypes ([#2622](https://github.com/OptimalBits/bull/issues/2622)) ([47722ed](https://github.com/OptimalBits/bull/commit/47722ed791429b087128ce5f35847663b2d8fc9c))
* **worker:** high-memory-usage-when-providing-float-to-concurrency ([#2620](https://github.com/OptimalBits/bull/issues/2620)) ([dcca1e8](https://github.com/OptimalBits/bull/commit/dcca1e8c39b121fb01ac299bec30a3d011059c1f))
* change option name to match ts declaration ([909a07e](https://github.com/OptimalBits/bull/commit/909a07e27075a63b9ca178a3074b0b5c80d86355))
* ts declaration metrics option and getMetrics function ([11331b7](https://github.com/OptimalBits/bull/commit/11331b718a8e534ac6822917a536eab32b10446b))


### Features

* upgrade ioredis to 5.3.2 ([e1883f0](https://github.com/OptimalBits/bull/commit/e1883f01c2cb23a51b5485ef8048c4268ee968ea))

## [4.10.4](https://github.com/OptimalBits/bull/compare/v4.10.3...v4.10.4) (2023-02-09)


### Bug Fixes

* **retry:** handle pause queue status ([9f945d6](https://github.com/OptimalBits/bull/commit/9f945d60c69e8b5d7b46f58189a1c49a83897099))

## [4.10.3](https://github.com/OptimalBits/bull/compare/v4.10.2...v4.10.3) (2023-02-03)


### Bug Fixes

* don't reschedule delay timer if closing ([#2535](https://github.com/OptimalBits/bull/issues/2535)) ([8a0292a](https://github.com/OptimalBits/bull/commit/8a0292a574df82a62d718e13d8995800fd8529d0))

## [4.10.2](https://github.com/OptimalBits/bull/compare/v4.10.1...v4.10.2) (2022-11-24)


### Bug Fixes

* **queue:** throw error when needed instead of hiding it in a closure ([8a742c1](https://github.com/OptimalBits/bull/commit/8a742c1176e7147e2069602f18089d8becb4cb15))

## [4.10.1](https://github.com/OptimalBits/bull/compare/v4.10.0...v4.10.1) (2022-10-13)


### Bug Fixes

* support for instantiation using redisUrl ([6288f7d](https://github.com/OptimalBits/bull/commit/6288f7de9b82e712e480510eb10c03bd4d1cd24e))

# [4.10.0](https://github.com/OptimalBits/bull/compare/v4.9.0...v4.10.0) (2022-09-29)


### Features

* **types:** add typescript types to package ([e793f8d](https://github.com/OptimalBits/bull/commit/e793f8d1502bc5ed4a2e15087dc048c18e5e8644))

# [4.9.0](https://github.com/OptimalBits/bull/compare/v4.8.5...v4.9.0) (2022-09-05)


### Features

* support .cjs files ([75e6775](https://github.com/OptimalBits/bull/commit/75e6775fc3720563aac9cd9a07d1722dfbdfa177))

## [4.8.5](https://github.com/OptimalBits/bull/compare/v4.8.4...v4.8.5) (2022-07-27)


### Performance Improvements

* **clean:** use ZRANGEBYSCORE to improve performance ([#2363](https://github.com/OptimalBits/bull/issues/2363)) ([3331188](https://github.com/OptimalBits/bull/commit/3331188bce510e0bb4749d92cb63f4c73203d076))

## [4.8.4](https://github.com/OptimalBits/bull/compare/v4.8.3...v4.8.4) (2022-06-16)


### Bug Fixes

* **worker:** better disconnect when blocking connection ([b9ea7f4](https://github.com/OptimalBits/bull/commit/b9ea7f4780948d4556548e6bf13e2c3271939d12))

## [4.8.3](https://github.com/OptimalBits/bull/compare/v4.8.2...v4.8.3) (2022-05-12)


### Bug Fixes

* **stalled-jobs:** move stalled jobs to wait in batches ([2f1fb6c](https://github.com/OptimalBits/bull/commit/2f1fb6cdc1329f98b2dd30e847b5a79839db0346))

## [4.8.2](https://github.com/OptimalBits/bull/compare/v4.8.1...v4.8.2) (2022-04-21)


### Bug Fixes

* unlock job when moving it to delayed ([#2329](https://github.com/OptimalBits/bull/issues/2329)) ([11eae6b](https://github.com/OptimalBits/bull/commit/11eae6b960c83b47dadb22991b2b3e239c177508))

## [4.8.1](https://github.com/OptimalBits/bull/compare/v4.8.0...v4.8.1) (2022-03-21)


### Performance Improvements

* speed up clean operation ([#2326](https://github.com/OptimalBits/bull/issues/2326)) ([ef5f471](https://github.com/OptimalBits/bull/commit/ef5f4717258940042fa11f980622034cde765860))

# [4.8.0](https://github.com/OptimalBits/bull/compare/v4.7.0...v4.8.0) (2022-03-19)


### Features

* have Queue#clean consult job.{finishedOn,processedOn,timestamp} ([#2309](https://github.com/OptimalBits/bull/issues/2309)) ([b7058e6](https://github.com/OptimalBits/bull/commit/b7058e6e8f4bb56febebaf9452f993883240fa9d))

# [4.7.0](https://github.com/OptimalBits/bull/compare/v4.6.2...v4.7.0) (2022-03-02)


### Features

* **metrics:** add support for collecting queue metrics ([886d764](https://github.com/OptimalBits/bull/commit/886d7643819dcf52902d2e92394267dbd495c71b))

## [4.6.2](https://github.com/OptimalBits/bull/compare/v4.6.1...v4.6.2) (2022-02-23)


### Bug Fixes

* better handling of maxRetriesPerRequest ([d3b9138](https://github.com/OptimalBits/bull/commit/d3b91386e30d7205efdc19bcd18fe1e5fefa3542))

## [4.6.1](https://github.com/OptimalBits/bull/compare/v4.6.0...v4.6.1) (2022-02-21)


### Bug Fixes

* **sandbox:** better error reporting broken processor file ([10db479](https://github.com/OptimalBits/bull/commit/10db479731bcb8ba27c3a0e2dd4094c8e9ff1c57))

# [4.6.0](https://github.com/OptimalBits/bull/compare/v4.5.6...v4.6.0) (2022-02-21)


### Features

* handle redis uri queries ([54e5463](https://github.com/OptimalBits/bull/commit/54e5463bffee1b8b56b460460c79d8751142d859))

## [4.5.6](https://github.com/OptimalBits/bull/compare/v4.5.5...v4.5.6) (2022-02-20)


### Bug Fixes

* **sandbox:** wait for result of sending start command ([232ed85](https://github.com/OptimalBits/bull/commit/232ed85d4c980d94dee5d9e4c5b6f8758dbb82d9))

## [4.5.5](https://github.com/OptimalBits/bull/compare/v4.5.4...v4.5.5) (2022-02-16)


### Bug Fixes

* **worker:** better closing when disconnected ([41b9404](https://github.com/OptimalBits/bull/commit/41b940457b3447619c3c2887674a8cebf1508b07))

## [4.5.4](https://github.com/OptimalBits/bull/compare/v4.5.3...v4.5.4) (2022-02-14)


### Bug Fixes

* **queue:** return correct workers with getWorkers() ([193644c](https://github.com/OptimalBits/bull/commit/193644c5ed290901448f8c35ede99e1063a90f4a))

## [4.5.3](https://github.com/OptimalBits/bull/compare/v4.5.2...v4.5.3) (2022-02-14)


### Bug Fixes

* **commands:** do not wait for redis to load commands ([ad7b647](https://github.com/OptimalBits/bull/commit/ad7b6474db426b4970a0d1d3ddb8a032a22c481b))

## [4.5.2](https://github.com/OptimalBits/bull/compare/v4.5.1...v4.5.2) (2022-02-14)


### Bug Fixes

* **scripts:** make it easier for tools like vercel to find the .lua scripts ([8ab5b1d](https://github.com/OptimalBits/bull/commit/8ab5b1d1c3eecf41b20d97f464030377ece01640))

## [4.5.1](https://github.com/OptimalBits/bull/compare/v4.5.0...v4.5.1) (2022-02-06)


### Bug Fixes

* **sandbox:** broken processor files should fail jobs ([dd0b853](https://github.com/OptimalBits/bull/commit/dd0b853a516c32baac535395377a19e361964dc8))

# [4.5.0](https://github.com/OptimalBits/bull/compare/v4.4.0...v4.5.0) (2022-02-01)


### Features

* **queue:** add retryJobs for failed status ([501b2cc](https://github.com/OptimalBits/bull/commit/501b2cc49ccd0d7de82fea50144b52fa9879d1f5))

# [4.4.0](https://github.com/OptimalBits/bull/compare/v4.3.0...v4.4.0) (2022-01-26)


### Features

* add support for removeOn based on time ([90f040c](https://github.com/OptimalBits/bull/commit/90f040c052325da302c99f17111a12d1afbe88bd))

# [4.3.0](https://github.com/OptimalBits/bull/compare/v4.2.1...v4.3.0) (2022-01-26)


### Features

* upgrade cron version enabling new cron expressions ([79337a3](https://github.com/OptimalBits/bull/commit/79337a30758ea7e6d6b1536eb0edebcd0b3c8274))

## [4.2.1](https://github.com/OptimalBits/bull/compare/v4.2.0...v4.2.1) (2022-01-17)


### Bug Fixes

* **sandbox:** exit if uncaughtException ([43dc2e6](https://github.com/OptimalBits/bull/commit/43dc2e69dfa0cbaf960ce6f1bd6c4125b1052ff9))

# [4.2.0](https://github.com/OptimalBits/bull/compare/v4.1.4...v4.2.0) (2021-12-21)


### Features

* **queue:** enabled queues to share childPool instance ([#2237](https://github.com/OptimalBits/bull/issues/2237)) ([16fdbe9](https://github.com/OptimalBits/bull/commit/16fdbe90a05ae2e2bcb134a550a97dc84dfe573e))

## [4.1.4](https://github.com/OptimalBits/bull/compare/v4.1.3...v4.1.4) (2021-12-14)


### Bug Fixes

* **queue:** check redisOptions is available fixes [#2186](https://github.com/OptimalBits/bull/issues/2186) ([071c51d](https://github.com/OptimalBits/bull/commit/071c51d16db58ed9f71138058dbbc25f73383e56))

## [4.1.3](https://github.com/OptimalBits/bull/compare/v4.1.2...v4.1.3) (2021-12-14)


### Bug Fixes

* typo on url ([#2195](https://github.com/OptimalBits/bull/issues/2195)) ([7e7d9cb](https://github.com/OptimalBits/bull/commit/7e7d9cb58d7cb5c1a92020f7c4333932526d8e98))

## [4.1.2](https://github.com/OptimalBits/bull/compare/v4.1.1...v4.1.2) (2021-12-14)


### Performance Improvements

* speed up performance of queue.clean when called with a limit ([#2205](https://github.com/OptimalBits/bull/issues/2205)) ([c20e469](https://github.com/OptimalBits/bull/commit/c20e469dcd71fd13e23e922f2720f55450311d22))

## [4.1.1](https://github.com/OptimalBits/bull/compare/v4.1.0...v4.1.1) (2021-11-16)


### Bug Fixes

* **emit:** protect emit calls fixes [#2213](https://github.com/OptimalBits/bull/issues/2213) ([4978a2b](https://github.com/OptimalBits/bull/commit/4978a2b40ee840ba91e0939e86e1e3b15e8b16e9))

# [4.1.0](https://github.com/OptimalBits/bull/compare/v4.0.0...v4.1.0) (2021-10-31)


### Features

* emit event on job lock extend failure ([7247b3b](https://github.com/OptimalBits/bull/commit/7247b3bb9741c5eb18ce4027ea14349cbc8504c5))

# [4.0.0](https://github.com/OptimalBits/bull/compare/v3.29.3...v4.0.0) (2021-10-27)


### Bug Fixes

* force options to guarantee correct reconnects ([3ade8e6](https://github.com/OptimalBits/bull/commit/3ade8e6727d7b906a30b09bccb6dc10d76ed1b5f))


### BREAKING CHANGES

* If redis opts are missing:
 { maxRetriesPerRequest: null,
   enableReadyCheck: false }
then a exception will be thrown.

## [3.29.3](https://github.com/OptimalBits/bull/compare/v3.29.2...v3.29.3) (2021-10-13)


### Bug Fixes

* **name-processors:** wait for all processors when closing fixes [#1618](https://github.com/OptimalBits/bull/issues/1618) ([79ce013](https://github.com/OptimalBits/bull/commit/79ce013af695f96ff57106b213982647e0783d3f))

## [3.29.2](https://github.com/OptimalBits/bull/compare/v3.29.1...v3.29.2) (2021-09-08)


### Bug Fixes

* **connection:** fail only if redis connection does not recover ([0ca4c6b](https://github.com/OptimalBits/bull/commit/0ca4c6b4d57efa78e5ca484cb8bed2a6961646a3))

## [3.29.1](https://github.com/OptimalBits/bull/compare/v3.29.0...v3.29.1) (2021-08-26)


### Bug Fixes

* protect getJob with isReady, fixes [#1386](https://github.com/OptimalBits/bull/issues/1386) ([2f27faa](https://github.com/OptimalBits/bull/commit/2f27faa410f70504f24df2ebd6bb7831df21660d))

# [3.29.0](https://github.com/OptimalBits/bull/compare/v3.28.1...v3.29.0) (2021-08-20)


### Features

* **jobs:** add extendLock method ([30d5959](https://github.com/OptimalBits/bull/commit/30d59590c34cb664e3b9a62695c4092c9b1ae3f3))

## [3.28.1](https://github.com/OptimalBits/bull/compare/v3.28.0...v3.28.1) (2021-08-06)


### Bug Fixes

* **queue:** changed user prop to username for redisOptions ([71baea9](https://github.com/OptimalBits/bull/commit/71baea91de702d9bd1d5516f09b22599b7f13045))

# [3.28.0](https://github.com/OptimalBits/bull/compare/v3.27.0...v3.28.0) (2021-08-05)


### Features

* **queue:** handle redis url containing username ([a245fc4](https://github.com/OptimalBits/bull/commit/a245fc403827fd22b08dbe1499fe843eb1ad633a))

# [3.27.0](https://github.com/OptimalBits/bull/compare/v3.26.0...v3.27.0) (2021-07-27)


### Features

* support job.discard function in sandboxed processors ([5adcf2c](https://github.com/OptimalBits/bull/commit/5adcf2ceed263d46089cceefcdcaa658151c53b7))

# [3.26.0](https://github.com/OptimalBits/bull/compare/v3.25.2...v3.26.0) (2021-07-16)


### Features

* **repeatable:** store key in repeat options ([dab0d82](https://github.com/OptimalBits/bull/commit/dab0d8266174f1d25ec914cff8450594d85db511))

## [3.25.2](https://github.com/OptimalBits/bull/compare/v3.25.1...v3.25.2) (2021-07-16)


### Bug Fixes

* **repeatable:** honor endDate fixes [#1573](https://github.com/OptimalBits/bull/issues/1573) ([7f0db0e](https://github.com/OptimalBits/bull/commit/7f0db0e293367752971be8a1bf7b6c8cf4190350))

## [3.25.1](https://github.com/OptimalBits/bull/compare/v3.25.0...v3.25.1) (2021-07-16)


### Bug Fixes

* error when .lua scripts missing in built bundle ([85307c3](https://github.com/OptimalBits/bull/commit/85307c3a8e48b910590b2682700c5062c84d32b0))

# [3.25.0](https://github.com/OptimalBits/bull/compare/v3.24.0...v3.25.0) (2021-07-15)


### Features

* pass clientName to createClient function ([2a29569](https://github.com/OptimalBits/bull/commit/2a295691b88318ff64beaa7b83e03487854a7fe4))

# [3.24.0](https://github.com/OptimalBits/bull/compare/v3.23.3...v3.24.0) (2021-07-15)


### Features

* **backoff:** add option to specify options for custom backoff strategy ([e573010](https://github.com/OptimalBits/bull/commit/e5730107688a41c7268a717f16302c5959eaf6f6))

## [3.23.3](https://github.com/OptimalBits/bull/compare/v3.23.2...v3.23.3) (2021-07-15)


### Bug Fixes

* **delayed:** do not get lock twice fixes [#2033](https://github.com/OptimalBits/bull/issues/2033) ([2800cf8](https://github.com/OptimalBits/bull/commit/2800cf8923ccac52dcd4da4e7fd19b3404c68fe8))

## [3.23.2](https://github.com/OptimalBits/bull/compare/v3.23.1...v3.23.2) (2021-07-15)


### Bug Fixes

* **job:** add default err object fixes [#2029](https://github.com/OptimalBits/bull/issues/2029) ([39684e9](https://github.com/OptimalBits/bull/commit/39684e9f941e2ea4191809fdc2aa52b3d7b267ae))

## [3.23.1](https://github.com/OptimalBits/bull/compare/v3.23.0...v3.23.1) (2021-07-15)


### Bug Fixes

* wait in queue to be ready in getNextJob fixes [#1852](https://github.com/OptimalBits/bull/issues/1852) ([4e224e5](https://github.com/OptimalBits/bull/commit/4e224e5533f729b9781b1db81e1875b1bd50afb0))

# [3.23.0](https://github.com/OptimalBits/bull/compare/v3.22.12...v3.23.0) (2021-07-13)


### Features

* support job.update function in sandboxed processors ([ff79fb4](https://github.com/OptimalBits/bull/commit/ff79fb494ea3e123256b35d18b46b24fbb9b8365)), closes [#1279](https://github.com/OptimalBits/bull/issues/1279) [#1608](https://github.com/OptimalBits/bull/issues/1608) [#1056](https://github.com/OptimalBits/bull/issues/1056)

## [3.22.12](https://github.com/OptimalBits/bull/compare/v3.22.11...v3.22.12) (2021-07-13)


### Bug Fixes

* remove stalled job when finishing fixes [#1600](https://github.com/OptimalBits/bull/issues/1600) ([90763fd](https://github.com/OptimalBits/bull/commit/90763fd66404d8bc5a47ff8555cbe2da776c030d))

## [3.22.11](https://github.com/OptimalBits/bull/compare/v3.22.10...v3.22.11) (2021-07-08)


### Bug Fixes

* **close:** clear timers after waiting jobs fixes [#1415](https://github.com/OptimalBits/bull/issues/1415) ([77b319d](https://github.com/OptimalBits/bull/commit/77b319da6acaa93351830f0a4e38b5ad1d3d8cf5))

## [3.22.10](https://github.com/OptimalBits/bull/compare/v3.22.9...v3.22.10) (2021-07-01)


### Bug Fixes

* deep clone options ([#2083](https://github.com/OptimalBits/bull/issues/2083)) ([1e00a90](https://github.com/OptimalBits/bull/commit/1e00a90d1216083cdf33bc78a9753ece1acdddb2))

## [3.22.9](https://github.com/OptimalBits/bull/compare/v3.22.8...v3.22.9) (2021-06-22)


### Bug Fixes

* **reprocess:** do not store job.id in added list ([3fbc506](https://github.com/OptimalBits/bull/commit/3fbc506aee4c36fd612ed18fc3a1619c0c8069d8))

## [3.22.8](https://github.com/OptimalBits/bull/compare/v3.22.7...v3.22.8) (2021-06-09)


### Bug Fixes

* upgrade ioredis fixes [#1445](https://github.com/OptimalBits/bull/issues/1445) ([f6a2364](https://github.com/OptimalBits/bull/commit/f6a23648146f5a53bb2e4084f8de9b783b782bed))

## [3.22.7](https://github.com/OptimalBits/bull/compare/v3.22.6...v3.22.7) (2021-05-31)


### Bug Fixes

* **obliterate:** remove job logs fixes [#2050](https://github.com/OptimalBits/bull/issues/2050) ([6ccf2b9](https://github.com/OptimalBits/bull/commit/6ccf2b90892bf16b4edb0095d6e770f978bc660a))

## [3.22.6](https://github.com/OptimalBits/bull/compare/v3.22.5...v3.22.6) (2021-05-17)


### Bug Fixes

* **job:** fix job log pagination, fixes [#2031](https://github.com/OptimalBits/bull/issues/2031) ([30aa0a9](https://github.com/OptimalBits/bull/commit/30aa0a99acb4a04a12f988840bc8ccc7a014fed3))

## [3.22.5](https://github.com/OptimalBits/bull/compare/v3.22.4...v3.22.5) (2021-05-11)


### Bug Fixes

* emit failed event when stalled job fails ([f68da41](https://github.com/OptimalBits/bull/commit/f68da4176658b9935cf4b63b218130008619b25b))

## [3.22.4](https://github.com/OptimalBits/bull/compare/v3.22.3...v3.22.4) (2021-04-27)


### Bug Fixes

* also populate retriedOn when loading from id with excludeData ([0964b39](https://github.com/OptimalBits/bull/commit/0964b390d9190510f0d016f4eb2a3f1bc6cdb4e5))

## [3.22.3](https://github.com/OptimalBits/bull/compare/v3.22.2...v3.22.3) (2021-04-23)


### Bug Fixes

* **delayed:** re-schedule updateDelay in case of error fixes [#2015](https://github.com/OptimalBits/bull/issues/2015) ([16bbfad](https://github.com/OptimalBits/bull/commit/16bbfadb270bc6c7d6df9cf5ab30b7f66028b2b3))

## [3.22.2](https://github.com/OptimalBits/bull/compare/v3.22.1...v3.22.2) (2021-04-23)


### Bug Fixes

* **obliterate:** obliterate many jobs fixes [#2016](https://github.com/OptimalBits/bull/issues/2016) ([7a923b4](https://github.com/OptimalBits/bull/commit/7a923b468d5299bbdfe06d1ee7447fd810e2779b))


## v.3.22.1

- fix(obliterate): remove repeatable jobs fixes #2012

[Changes](https://github.com/OptimalBits/bull/compare/v3.22.0...v3.22.1)

## v.3.22.0

- feat: do not rely on comma to encode jobid in progress fixes #2003

[Changes](https://github.com/OptimalBits/bull/compare/v3.21.1...v3.22.0)


## v.3.21.1

- fix: safer implementation of obliterate.
Note: If you want to use the new method "obliterate" it is highly recommended
that you upgrade to this version, since previous version is not safe to use
if using the colon ':' character in your queue names.


[Changes](https://github.com/OptimalBits/bull/compare/v3.21.0...v3.21.1)

## v.3.21.0

- feat: add a method to "obliterate" a queue
- fix: upgrade lodash fixes #1996

[Changes](https://github.com/OptimalBits/bull/compare/v3.20.1...v3.21.0)

## v.3.20.1

- fix(queue): possible infinite loop when disconnect fixes #1746
- fix(clean-priority): remove job from priority set on clean (#1405)
- fix(sandbox): job update (#1957)
- fix: use async version of process.send for progress and log (#1948)
- fix: promote jobs to the right "list" when paused

[Changes](https://github.com/OptimalBits/bull/compare/v3.20.0...v3.20.1)

## v.3.20.0

- feat(job): implement Job#retriedOn (#1868)
- fix: job default opts fixes #1904

[Changes](https://github.com/OptimalBits/bull/compare/v3.19.1...v3.20.0)

## v.3.19.1

- fix(getters): properly zip hmget result

[Changes](https://github.com/OptimalBits/bull/compare/v3.19.0...v3.19.1)

## v.3.19.0

- feat: add option to exclude data on getters (#1910)
- fix: lock ioredis to 4.18.0 to avoid breakage with newer 4.19.0+.

[Changes](https://github.com/OptimalBits/bull/compare/v3.18.1...v3.19.0)

## v.3.18.1

- fix(repeat): remove last delayed job.
- fix(rate-limiter): increment jobCounter only when a job is processed. fixes #1875.
- fix(sandbox): clear dangling timeout.

[Changes](https://github.com/OptimalBits/bull/compare/v3.18.0...v3.18.1)

## v.3.18.0

- feat: make pause forward compatible with bullmq (#1818) (@manast)

[Changes](https://github.com/OptimalBits/bull/compare/v3.17.0...v3.18.0)

## v.3.17.0

- feat: better rate limiter (#1816) (@manast)
- feat(sandbox): kill child workers gracefully (#1802) (@GabrielCastro)

[Changes](https://github.com/OptimalBits/bull/compare/v3.16.0...v3.17.0)

## v.3.16.0

- feat(rate-limiter): add grouping support.

[Changes](https://github.com/OptimalBits/bull/compare/v3.15.0...v3.16.0)

## v.3.15.0

- feat: add isPaused fixes #1274
- fix: emit waiting event when adding a priority job (#1134)

[Changes](https://github.com/OptimalBits/bull/compare/v3.14.0...v3.15.0)

## v.3.14.0

- feat(queue): add removeJobs function
- fix: clamp negative job delay values to 0 to prevent thrashing
- fix: use DEFAULT_JOB_NAME (#1585)
- fix: remove the lazy client error handler on close (#1605)
- fix: prevent exceeding the maximum stack call size when emptying large queues (#1660)

[Changes](https://github.com/OptimalBits/bull/compare/v3.13.0...v3.14.0)

## v.3.13.0

- feat: add "preventParsingData" job option to prevent data parsing
- fix: queue.clean clean job logs as well
- fix: whenCurrentJobsFinished should wait for all jobs

[Changes](https://github.com/OptimalBits/bull/compare/v3.12.1...v3.13.0)

## v.3.12.1

- fix: catch errors parsing invalid progress data
- fix(pause): don't initialize bclient if not waiting for jobs to finish

[Changes](https://github.com/OptimalBits/bull/compare/v3.12.0...v3.12.1)

## v.3.12.0

- feat: support async custom backoffs.
- feat(sandbox): emulate job.progress function.

- fix: queue.pause(true, true) doesn't pause queue.

[Changes](https://github.com/OptimalBits/bull/compare/v3.11.0...v3.12.0)

## v.3.11.0

- feat(queue): basic support for bulk adding jobs.
- feat(job): save data on job instance when updated.

- fix(queue): whenCurrentJobsFinished shouldn't initialize bclient. Fixes #1346.
- fix(queue): unhandled promise warning in updateDelayTimer.
- fix(sandbox): if the child process is killed, remove it from the pool.

[Changes](https://github.com/OptimalBits/bull/compare/v3.10.0...v3.11.0)

## v.3.10.0

- fix: remove logs automtically when using autoremove fixes #1330
- feat: add support for keeping a specified number of jobs when using auto-remove.
- feat: add support for node 12
- fix: fix check for supported file types in sandboxed processors #1311
- ci: drop support for node 6

[Changes](https://github.com/OptimalBits/bull/compare/v3.9.1...v3.10.0)

## v.3.9.1

- fix: add log to job wrapper

[Changes](https://github.com/OptimalBits/bull/compare/v3.9.0...v3.9.1)

## v.3.9.0

- feat: add job.log #1165

[Changes](https://github.com/OptimalBits/bull/compare/v3.8.1...v3.9.0)

## v.3.8.1

- fix: wait for ready in cleanJobsInSet fixes #1298

[Changes](https://github.com/OptimalBits/bull/compare/v3.8.0...v3.8.1)

## v.3.8.0

- fix: improve delay logic fixing #1226, #1222
- feat: store finishedOn on the job instance
- fix: return every in getRepeatableJobs #1284
- fix: remove broken child processes #1098
- feat: update sandbox exit handler to log signals #1252
- fix: Ignore unknown command client error #1240

[Changes](https://github.com/OptimalBits/bull/compare/v3.7.0...v3.8.0)

## v.3.7.0

- perf: improve update delay set logic.
- feat: consider priority when promoting a job #1205.
- fix: better delay for rate limited jobs.
- feat: update port selection mechanism for child node process inspect flag.

[Changes](https://github.com/OptimalBits/bull/compare/v3.6.0...v3.7.0)

## v.3.6.0

- feat: add function to remove repeatable jobs by key.
- fix: properly remove sandbox events. Fixes #1179.
- fix: make progress functions in sandbox consistently return a promise.

[Changes](https://github.com/OptimalBits/bull/compare/v3.5.3...v3.6.0)

## v.3.5.3

- chore: upgrade ioredis to ^4.5.1.
- fix: fix #1044 support for typescript processors.
- chore: remove bluebird.
- chore: use lockKey method instead of private property.
- fix(queue): convert delay setting to number.

[Changes](https://github.com/OptimalBits/bull/compare/v3.5.2...v3.5.3)

## v.3.5.2

- chore(queue): remove bluebird config from the codebase.

[Changes](https://github.com/OptimalBits/bull/compare/v3.5.1...v3.5.2)

## v.3.5.1

- chore(yarn): updated yarn.lock

[Changes](https://github.com/OptimalBits/bull/compare/v3.5.0...v3.5.1)

## v.3.5.0

- fix(delayed): pause delayed jobs #1087
- fix(lua): correct numJobs fetch in moveToActive
- perf(moveToActive): used local var for rate limiter
- perf(queue): replace bluebird by native promises where possible
- chore(queue): fix typo in forcedReconnection variable
- feat(child-processes): catch sub process crashes
- fix(jobs): reset 'failedReason', 'finishedOn' and 'processedOn' fields on job retry
- fix(queue): fix Warning: cancellation is disabled
- fix(queue): remove the correct listener in isRedisReady
- feat(jobs): allow cancelling of retries when using custom backoff strategy
- feat(rate-limiter): add discard config for rate-limiter
- feat(jobs): make job progress accepts variant types
- fix(repeatable): Fixed wrong repeatable count updates
- fix(jobs): fix copy paste mistake for stacktrace in job toData
- feat(child-processes): Propagate stack traces
- feat(repeatable): add ability for cron repeatable job with startDate

[Changes](https://github.com/OptimalBits/bull/compare/v3.4.8...v3.5.0)

## v.3.4.8

- emit waiting event when waking up sleep jobs fixing #792
- throw error if missing processor file fixing #954

[Changes](https://github.com/OptimalBits/bull/compare/v3.4.7...v3.4.8)

## v.3.4.7

- Fixes to deal with removing correctly in priority queues #984

[Changes](https://github.com/OptimalBits/bull/compare/v3.4.6...v3.4.7)

## v.3.4.6

- Reverted use of arrow function that was incompatible with older versions of node.

[Changes](https://github.com/OptimalBits/bull/compare/v3.4.5...v3.4.6)

## v.3.4.5

- Fixed Unhandled promise rejections #1012.

[Changes](https://github.com/OptimalBits/bull/compare/v3.4.4...v3.4.5)

## v.3.4.4

- Partially fixed #845. When call queue.close() bull throws Error: Connection is closed.
- Fixed #998. Check for existence of rate limiter options.
- Fixed #1003. Fixed fixed repeatable jobs duplication using every.
- Feature/provide error to custom backoff strategy.

[Changes](https://github.com/OptimalBits/bull/compare/v3.4.3...v3.4.4)

## v.3.4.3

- Fixed #994 queue.getJobs() race condition.
- Fixed #966 Race conditions reviving repeatable jobs.
- Fixed getters: Update types array to include paused.
- Fixed #958 job.finished slowdown.
- Fixed #949 TypeError: job.queue.client.isFinished is not a function.
- Fixed #870 TypeError when retrying jobs.
- Fixed #942 Support for milliseconds intervals in repeatable jobs.

[Changes](https://github.com/OptimalBits/bull/compare/v3.4.2...v3.4.3)

## v.3.4.2

- Fixed #903 Globally paused queue cannot receive job (or not shown in Arena untill queue is globally resumed).
- Workaround for #911 Seperate process worker fails to launch when Node is started with --inspect flag
- added missing retain on reused child job #908.
- added more tests for child jobs.

[Changes](https://github.com/OptimalBits/bull/compare/v3.4.1...v3.4.2)

## v.3.4.1

- Better check for closing in moveUnlockedJobsToWait, possibly fixing #806.

[Changes](https://github.com/OptimalBits/bull/compare/v3.4.0...v3.4.1)

## v.3.4.0

- Added support for prioritized delayed jobs.
- Added ability to process all named jobs from one process function.
- Fixed #893, warning 'a promise was rejected with a non-error' for external queues in case of an error.

[Changes](https://github.com/OptimalBits/bull/compare/v3.3.10...v3.4.0)

## v.3.3.10

- Faster next job fetch #868
- Added global default options for jobs. Fixes #706.
- Added a limit for repeatable jobs. #854.

[Changes](https://github.com/OptimalBits/bull/compare/v3.3.9...v3.3.10)

## v.3.3.9

- Support custom backoff strategies.
- Fixed #786. Handling of ES6 default export.
- Fixed #782. Better handling of "isReady".

[Changes](https://github.com/OptimalBits/bull/compare/v3.3.8...v3.3.9)

## v.3.3.8

- Fixed #812. External process doesn't terminate on `queue.close()`.
- Fixed #830. Named Process Sent to Wrong Processor.
- Fixed #572. Do not close external connections.

[Changes](https://github.com/OptimalBits/bull/compare/v3.3.7...v3.3.8)

## v.3.3.7

- Fixed #807.
- Adding ability to limit by stacktrace. #798.

[Changes](https://github.com/OptimalBits/bull/compare/v3.3.6...v3.3.7)

## v.3.3.6

- Fixed #766, #781, #716.
- Correctly accept DB in redis connection string.
- Fixed global progress event.

[Changes](https://github.com/OptimalBits/bull/compare/v3.3.5...v3.3.6)

## v.3.3.5

- Fixed #764, #762, #759.

[Changes](https://github.com/OptimalBits/bull/compare/v3.3.4...v3.3.5)

## v.3.3.4

- Fixed #748.

[Changes](https://github.com/OptimalBits/bull/compare/v3.3.3...v3.3.4)

## v.3.3.3

- Re-fixed #739.
- Possibly fixed for #747.
- Fixed removeRepeatable (missing file)

[Changes](https://github.com/OptimalBits/bull/compare/v3.3.2...v3.3.3)

## v.3.3.2

- Fixed #721. SyntaxError: Unexpected token u in JSON at position 0.
- Fixed #739. childs are not added to the retained set.
- Fixed #734. fixed Promise warnings.

[Changes](https://github.com/OptimalBits/bull/compare/v3.3.1...v3.3.2)

## v.3.3.1

- Fixed #714

[Changes](https://github.com/OptimalBits/bull/compare/v3.3.0...v3.3.1)

## v.3.3.0

- Added a method `Queue##removeRepeatable` to remove repeatable jobs.
- Now also emits drained as a global event.
- Fixed #518, #624

[Changes](https://github.com/OptimalBits/bull/compare/v3.2.0...v3.3.0)

## v.3.2.0

- Added support for running jobs in child processes #488

[Changes](https://github.com/OptimalBits/bull/compare/v3.1.0...v3.2.0)

## v.3.1.0

- Added rate limiter support.
- Added method to update jobs data.
- Implemented stalled as global event.

[Changes](https://github.com/OptimalBits/bull/compare/v3.0.0...v3.1.0)

## v.3.0.0

- No changes.

## v.3.0.0-rc.10

- Fixed #666.
- Small improvements in the repeat code.

[Changes](https://github.com/OptimalBits/bull/compare/v3.0.0-rc.9...v3.0.0-rc.10)

## v.3.0.0-rc.9

- Fixed #672.
- Fixed #670

[Changes](https://github.com/OptimalBits/bull/compare/v3.0.0-rc.8...v3.0.0-rc.9)

## v.3.0.0-rc.8

- Enhanced job fetching #651 (faster and more reliable).

[Changes](https://github.com/OptimalBits/bull/compare/v3.0.0-rc.7...v3.0.0-rc.8)

## v.3.0.0-rc.7

- Fixed #659

[Changes](https://github.com/OptimalBits/bull/compare/v3.0.0-rc.6...v3.0.0-rc.7)

## v.3.0.0-rc.6

- Fixed #645.

[Changes](https://github.com/OptimalBits/bull/compare/v3.0.0-rc.5...v3.0.0-rc.6)

## v.3.0.0-rc.5

- Improved performance, specially when having many concurrent workers.
- Fixed #609 using zsets for storing repeatable jobs.
- Fixed #608 Event chaining no longer works.
- Improved getters.
- Fixed #601 Add multiple repeatable jobs with the same cron pattern.

[Changes](https://github.com/OptimalBits/bull/compare/3.0.0-rc.4...v3.0.0-rc.5)

## v.3.0.0-rc.4

- Added support for naming workers in redis connections #530.
- Lazy instantiation of redis clients. Fixes #526.
- job.finished captures result from queue process. #588.
- Caches LUA scripts to avoid reading files in every queue instantiation. #591.
- Emit 'drain' event when queue is empty. #596.
- store finished and processed timestamps. #594, #606.

[Changes](https://github.com/OptimalBits/bull/compare/v3.0.0-rc.3...3.0.0-rc.4)

## v.3.0.0-rc.3

- Fixed #579.
- Lazy subscription to events for better performance.
- Corrected calculation of next repeat job. #563.

[Changes](https://github.com/OptimalBits/bull/compare/v3.0.0-rc.2...v3.0.0-rc.3)

## v.3.0.0-rc.2

- Improved performance of moveToActive #550.
- Fixed issue with cancelable promise #546.

[Changes](https://github.com/OptimalBits/bull/compare/v3.0.0-rc.1...v3.0.0-rc.2)

## v.3.0.0-rc.1

- Improved error and lock handling for failed jobs #499, #539.
- Corrected instantiation from urls #538.
- Return jobs in proper order in jobs getters.

[Changes](https://github.com/OptimalBits/bull/compare/v3.0.0-alpha.4...v3.0.0-rc.1)

## v.3.0.0-alpha.4

- Implemented repeatable jobs. #252.

[Changes](https://github.com/OptimalBits/bull/compare/v3.0.0-alpha.3...v3.0.0-alpha.4)

## v.3.0.0-alpha.3

- Simplified global events #501.

[Changes](https://github.com/OptimalBits/bull/compare/v3.0.0-alpha.2...v3.0.0-alpha.3)

## v.3.0.0-alpha.2

- Eliminated possible memory leak #503

[Changes](https://github.com/OptimalBits/bull/compare/v3.0.0-alpha.1...v3.0.0-alpha.2)

## v.3.0.0-alpha.1

- improved job fetch mechanism. #480.
- job.jobId changed to job.id.
- refactored error messages into separate error module.
- refactored lua scripts into separate files, and preloaded.
- many atomizations and clean ups.
- completed and failed job states are now represented in ZSETs. #190.

[Changes](https://github.com/OptimalBits/bull/compare/v2.2.6...v3.0.0-alpha.1)

## v.2.2.6

- Persisted failedReason when storing job data.
- added queue##isReady()

[Changes](https://github.com/OptimalBits/bull/compare/v2.2.5...v2.2.6)

## v.2.2.5

- Fixed so that redis key prefix works properly.

[Changes](https://github.com/OptimalBits/bull/compare/v2.2.4...v2.2.5)

## v.2.2.4

- Allow reusing certain redis connections.

[Changes](https://github.com/OptimalBits/bull/compare/v2.2.3...v2.2.4)

## v.2.2.3

- Added getJobCounts.
- Fixed global events #394.

[Changes](https://github.com/OptimalBits/bull/compare/v2.2.2...v2.2.3)

## v.2.2.2

- Fixed redis script cache gets bloated after update to bull 2.0 #426

[Changes](https://github.com/OptimalBits/bull/compare/v2.2.1...v2.2.2)

## v.2.2.1

- Re-added createClient option that was removed by mistake.
- Corrected getJobCountByTypes, fixes #419 and #401

[Changes](https://github.com/OptimalBits/bull/compare/v2.2.0...v2.2.1)

## v.2.2.0

- Much improved priority queues, simpler, faster and more reliable.
- Fixed issue where lua scripts where leaking memory.
- Improvements in local pause, fixing #446 and #447.
- Fix to increase delay time over 24 days #244

[Changes](https://github.com/OptimalBits/bull/compare/v2.1.2...v2.2.0)

## v.2.1.2

- Fixed Error renewing lock LockError: Exceeded 0 attempts to lock the resource #437
- Fixed Unable to renew nonexisting lock on job fail #441

[Changes](https://github.com/OptimalBits/bull/compare/v2.1.1...v2.1.2)

## v.2.1.1

- Catch errors produced in timers. Related to #441

[Changes](https://github.com/OptimalBits/bull/compare/v2.1.0...v2.1.1)

## v.2.1.0

- Fixed #397, Error: Unable to renew nonexisting lock
- Fixed #402, Job.prototype.finished contains error in promise
- Fixed #371, "Unexpected token u in JSON at position 0" while processing job
- New feature #363, "method to permanently fail a job"
- Fix job.progress() to return the correct progress

[Changes](https://github.com/OptimalBits/bull/compare/v2.0.0...v2.1.0)

## v.2.0.0

- Changed redis module to ioredis fixing many issues along the way, see changes.

[Changes](https://github.com/OptimalBits/bull/compare/v1.1.3...v2.0.0)

## v.1.1.3

- fixed "Broken constructor pattern from recent commit" #384
- fixed "Queue.prototype.getWaiting() returns empty list if Queue is paused" #342

[Changes](https://github.com/OptimalBits/bull/compare/v1.1.2...v1.1.3)

## v1.1.2

- regained backwards compatibility in events by using disturbed 1.0.6

[Changes](https://github.com/OptimalBits/bull/compare/v1.1.1...v1.1.2)

## v1.1.1

- Returned this in queue##on and queue##once for backwards compatibility.
- [Fixes PriorityQueue Events and Local Worker Pause/Resume](https://github.com/OptimalBits/bull/pull/341)

[Changes](https://github.com/OptimalBits/bull/compare/v1.1.0...v1.1.1)

## v1.1.0

- Fixed [job corruption issue](https://github.com/OptimalBits/bull/pull/359)
- The job id can be [overridden](https://github.com/OptimalBits/bull/pull/335) to implement job throttling behavior
- Added [`removeOnComplete` job option](https://github.com/OptimalBits/bull/pull/361)
- [More robust job retry](https://github.com/OptimalBits/bull/pull/318)
- Events are [now broadcast to all workers](https://github.com/OptimalBits/bull/commit/d55ad1c8f44f86be9b4e9f4fa9a3fc8a16c6e02d)

[Changes](https://github.com/OptimalBits/bull/compare/v1.0.0...v1.1.0)

## v1.0.0

- improvements in clean (fixes and performance).

[Changes](https://github.com/OptimalBits/bull/compare/v1.0.0-rc4...v1.0.0)

## v1.0.0-rc4

- fixed lock renew logic.
- atomized code for getting stalled jobs.

[Changes](https://github.com/OptimalBits/bull/compare/v1.0.0-rc3...v1.0.0-rc4)

## v1.0.0-rc3

- smaller fixes.

[Changes](https://github.com/OptimalBits/bull/compare/v1.0.0-rc2...v1.0.0-rc3)

## v1.0.0-rc2

- Improved locking when removing and processing stalled jobs.
- Fixed #302 EVALSHA failure.
- Fixed #295 error with redis 3.2.
- Correctly allows the specification of the db
- Honor start/end range for complete/failed jobs.
- Fixed #277 Memory Leaks With Large Queue.
- Support for custom key prefix for redis keys.

[Changes](https://github.com/OptimalBits/bull/compare/v1.0.0-rc1...v1.0.0-rc2)

## v1.0.0-rc1

- Removed all potential dangerous hazards by atomizing many operations using
  cached LUA scripts.
- Improved performance around 400% compared to previous version.
- Better pause/resume (#266), and added pause for local workers.
- Fixed #272, #271, #261, #253, #240, #239

[Changes](https://github.com/OptimalBits/bull/compare/v0.7.2...v1.0.0-rc1)

## v0.7.2

- Added local pause/resume functionality
- fixed memory leaks present in the run promise chain.
- fixed "Illegal access to a strict mode caller function".

[Changes](https://github.com/OptimalBits/bull/compare/v0.7.1...v0.7.2)

## v0.7.1

- fixed storing of stacktraces

[Changes](https://github.com/OptimalBits/bull/compare/v0.7.0...v0.7.1)

## v0.7.0

- store the return value from the job handlers.
- store stacktraces.
- improvements in delayed jobs.

[Changes](https://github.com/OptimalBits/bull/compare/v0.6.0...v0.7.0)

## v0.4.0

- added a Queue##clean method

[Changes](https://github.com/OptimalBits/bull/compare/v0.3.0...v0.4.0)

## v0.3.0

- added support for custom clients.
- added test support for node 0.12.
- timeout improvements.
- unit test improvements.
- added timeout to queue pop blocking call.
- removed when dependency.

[Changes](https://github.com/OptimalBits/bull/compare/v0.2.7...v0.3.0)

## v0.2.7

[Changes](https://github.com/OptimalBits/bull/compare/v0.2.6...v0.2.7)

## v0.2.6

- [Fix] #103 When a queue start it do not process delayed job.
  [Changes](https://github.com/OptimalBits/bull/compare/v0.2.5...v0.2.6)

## v0.2.5

- [upgrade] Upgraded node redis to version 0.12.x
- [improvement] eslinted all code.
- [fix] added missing token when calling takeLock on jobs.

[Changes](https://github.com/OptimalBits/bull/compare/v0.2.4...v0.2.5)

## v0.2.4

[Changes](https://github.com/OptimalBits/bull/compare/v0.2.3...v0.2.4)

## v0.2.3

[Changes](https://github.com/OptimalBits/bull/compare/v0.1.9...v0.2.3)

## v0.1.9

- [Improvement] Faster job removal. (manast)

## v0.1.8

- [Improvement] Better promisification of redis methods. (manast)

## v0.1.7

- [Feature] Added a convenience method for getting a job. (loginx)
- [Fix] Only set a redis db from options if defined. (jboga)
- [Fix] Fixed issue #52. (manast)

## v0.1.6

- [Fix] Improved and corrected job's getters.
- [Fix] Automatically restart queues in the event of redis disconnections.
- [Feature] Added support for adding jobs in a LIFO fashion.


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at manuel@optimalbits.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]

[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/


================================================
FILE: CONTRIBUTING.md
================================================
Release process
---------------

First, update `CHANGELOG.md` with the release number about to be released.

    npm outdated --depth 0          # See if you can upgrade any dependencies
    npm version [major|minor|patch] # Update package.json
    npm publish                     # Tag repo and publish npm package


================================================
FILE: LICENSE.md
================================================

License
-------

(The MIT License)

Copyright &copy; 2013-2018 Manuel Astudillo <manuel@optimalbits.com>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: MIGRATION.md
================================================
# Migration from 2.x to 3.0.0

Although version 3.0 is almost backwards compatible with 2.x, there are some important changes that needs
to be taking in consideration before upgrading to 3.0.

# Complete and failed sets.

In 3.x, the jobs that are completed and failed end in two ZSETS, instead of a standard SET.
This gives the possibility of retrieving a subset of the jobs in a high performant way, which
is useful for graphical tools and scripts. However an old queue will not be compatible with 3.x.
You will need to either delete the complete and failed keys, or create a new queue.

# Data structure changes

job.jobId to job.id

toJSON ->
 job.data
 job.opts

# Queue instantiation options

Sanitized and cleaned all the options. Check the [Reference](./REFERENCE.md) to see the new structure.


# Events

All events are now published atomically in the scripts where they are relevant, this increases efficiency and
reduces chances for hazards.

'ready' event has been removed, you can use ```Queue##isReady()``` instead if you want to know when the queue
has been initialized. Normally you will never need to wait for readyness since this is taken care internally
by the queue methods that require the queue to be ready.

Events arguments are now the same for local and global events. This affects events such as completed and failed,
where in 2.x the first argument was a job instance for local jobs. Now both local and global events pass
jobId as first argument to the event handler. If the job instance is needed it can be easily retrieved with
```Job.fromId()```.



================================================
FILE: PATTERNS.md
================================================

Patterns
========

Here are a few examples of useful patterns that are often implemented with Bull:

- [Message Queue](#message-queue)
- [Returning Job Completions](#returning-job-completions)
- [Reusing Redis Connections](#reusing-redis-connections)
- [Redis Cluster](#redis-cluster)
- [Debugging](#debugging)
- [Custom backoff strategy](#custom-backoff-strategy)
- [Manually fetching jobs](#manually-fetching-jobs)

If you have any other common patterns you want to add, pull request them!


Message Queue
-------------

Bull can also be used for persistent message queues. This is a quite useful
feature in some use cases. For example, you can have two servers that need to
communicate with each other. By using a queue the servers do not need to be online at the same time, so this creates a very robust communication channel. You can treat `add` as *send* and `process` as *receive*:

Server A:

```js
const Queue = require('bull');

const sendQueue = new Queue('Server B');
const receiveQueue = new Queue('Server A');

receiveQueue.process(function (job, done) {
  console.log('Received message', job.data.msg);
  done();
});

sendQueue.add({ msg: 'Hello' });
```

Server B:

```js
const Queue = require('bull');

const sendQueue = new Queue('Server A');
const receiveQueue = new Queue('Server B');

receiveQueue.process(function (job, done) {
  console.log('Received message', job.data.msg);
  done();
});

sendQueue.add({ msg: 'World' });
```


Returning Job Completions
-------------------------

A common pattern is where you have a cluster of queue processors that just process jobs as fast as they can, and some other services that need to take the result of this processors and do something with it, maybe storing results in a database.

The most robust and scalable way to accomplish this is by combining the standard job queue with the message queue pattern: a service sends jobs to the cluster just by opening a job queue and adding jobs to it, and the cluster will start processing as fast as it can. Everytime a job gets completed in the cluster a message is sent to a results message queue with the result data, and this queue is listened by some other service that stores the results in a database.


Reusing Redis Connections
-------------------------

A standard queue requires **3 connections** to the Redis server. In some situations you might want to re-use connections—for example on Heroku where the connection count is restricted. You can do this with the `createClient` option in the `Queue` constructor.

Notes:
- bclient connections [cannot be re-used](https://github.com/OptimalBits/bull/issues/880), so you should return a new connection each time this is called.
- client and subscriber connections can be shared and will not be closed when the queue is closed.  When you are shutting down the process, first close the queues, then the shared connections (if they are shared).
- if you are not sharing connections but still using `createClient` to do some custom connection logic, you may still need to keep a list of all the connections you created so you can manually close them later when the queue shuts down, if you need a graceful shutdown for your process
- do not set a `keyPrefix` on the connection you create, use bull's built-in prefix feature if you need a key prefix

```js
const { REDIS_URL } = process.env;

const Redis = require('ioredis');
let client;
let subscriber;

const opts = {
  // redisOpts here will contain at least a property of connectionName which will identify the queue based on its name
  createClient: function (type, redisOpts) {
    switch (type) {
      case 'client':
        if (!client) {
          client = new Redis(REDIS_URL, redisOpts);
        }
        return client;
      case 'subscriber':
        if (!subscriber) {
          subscriber = new Redis(REDIS_URL, redisOpts);
        }
        return subscriber;
      case 'bclient':
        return new Redis(REDIS_URL, redisOpts);
      default:
        throw new Error('Unexpected connection type: ' + type);
    }
  }
}

const queueFoo = new Queue('foobar', opts);
const queueQux = new Queue('quxbaz', opts);
```

Redis cluster
-------------

Bull internals require atomic operations that span different keys. This behavior breaks Redis's
rules for cluster configurations. However, it is still possible to use a cluster environment
by using the proper bull prefix option as a cluster "hash tag". Hash tags are used to guarantee
that certain keys are placed in the same hash slot, read more about hash tags in the [redis cluster
tutorial](https://redis.io/topics/cluster-tutorial). A hash tag is defined with brackets. I.e. a key that has a substring inside brackets will use that
substring to determine in which hash slot the key will be placed.

In summary, to make bull compatible with Redis cluster, use a queue prefix inside brackets.
For example:

```js
const queue = new Queue('cluster', {
  prefix: '{myprefix}'
});
```

If you use several queues in the same cluster, you should use different prefixes so that the
queues are evenly placed in the cluster nodes.

Debugging
---------

To see debug statements set or add `bull` to the `NODE_DEBUG` environment variable:

```bash
export NODE_DEBUG=bull
```

```bash
NODE_DEBUG=bull node ./your-script.js
```

Custom backoff strategy
-----------------------

When the builtin backoff strategies on retries are not sufficient, a custom strategy can be defined. Custom backoff strategies are defined by a function on the queue. The number of attempts already made to process the job is passed to this function as the first parameter, and the error that the job failed with as the second parameter.
The function returns either the time to delay the retry with, 0 to retry immediately or -1 to fail the job immediately.

```js
const Queue = require('bull');

const myQueue = new Queue('Server B', {
  settings: {
    backoffStrategies: {
      jitter: function (attemptsMade, err) {
        return 5000 + Math.random() * 500;
      }
    }
  }
});
```

The new backoff strategy can then be specified on the job, using the name defined above:

```js
myQueue.add({foo: 'bar'}, {
  attempts: 3,
  backoff: {
    type: 'jitter'
  }
});
```

You may specify options for your strategy:
```js
const Queue = require('bull');

const myQueue = new Queue('Server B', {
  settings: {
    backoffStrategies: {
      // truncated binary exponential backoff
      binaryExponential: function (attemptsMade, err, options) {
        // Options can be undefined, you need to handle it by yourself
        if (!options) {
          options = {}
        }
        const delay = options.delay || 1000;
        const truncate = options.truncate || 1000;
        console.error({ attemptsMade, err, options });
        return Math.round(Math.random() * (Math.pow(2, Math.max(attemptsMade, truncate)) - 1) * delay)
      }
    }
  }
});

myQueue.add({ foo: 'bar' }, {
  attempts: 10,
  backoff: {
    type: 'binaryExponential',
    options: {
      delay: 500,
      truncate: 5
    }
  }
});

```

You may base your backoff strategy on the error that the job throws:
```js
const Queue = require('bull');

function MySpecificError() {};

const myQueue = new Queue('Server C', {
  settings: {
    backoffStrategies: {
      foo: function (attemptsMade, err) {
        if (err instanceof MySpecificError) {
          return 10000;
        }
        return 1000;
      }
    }
  }
});

myQueue.process(function (job, done) {
  if (job.data.msg === 'Specific Error') {
    throw new MySpecificError();
  } else {
    throw new Error();
  }
});

myQueue.add({ msg: 'Hello' }, {
  attempts: 3,
  backoff: {
    type: 'foo'
  }
});

myQueue.add({ msg: 'Specific Error' }, {
  attempts: 3,
  backoff: {
    type: 'foo'
  }
});
```

Manually fetching jobs
----------------------------------

If you want the actual job processing to be done in a seperate repo/service than where `bull` is running, this pattern may be for you.

Manually transitioning states for jobs can be done with a few simple methods.

1. Adding a job to the 'waiting' queue. Grab the queue and call `add`.

```typescript
import Queue from 'bull';

const queue = new Queue({
  limiter: {
    max: 5,
    duration: 5000,
    bounceBack: true // important
  },
  ...queueOptions
});
queue.add({ random_attr: 'random_value' });
```

2. Pulling a job from 'waiting' and moving it to 'active'.

```typescript
const job: Job = await queue.getNextJob();
```

3. Move the job to the 'failed' queue if something goes wrong.

```typescript
const (nextJobData, nextJobId) = await job.moveToFailed(
  {
    message: 'Call to external service failed!',
  },
  true,
);
```

3. Move the job to the 'completed' queue.

```typescript
const (nextJobData, nextJobId) = await job.moveToCompleted('succeeded', true);
```

4. Return the next job if one is returned.

```typescript
if (nextJobdata) {
  return Job.fromJSON(queue, nextJobData, nextJobId);
}
```

**Note**

By default the lock duration for a job that has been returned by ```getNextJob``` or ```moveToCompleted``` is 30 seconds, if it takes more time than that the job will be automatically
marked as stalled and depending on the max stalled options be moved back to the wait state or marked as failed. In order to avoid this you must use [```job.extendLock(duration)```](REFERENCE.md#jobextendlock) in order to give you some more time before the lock expires. The recommended is to extend the lock when half the lock time has passsed.



================================================
FILE: README.md
================================================

<div align="center">
  <br/>
  <img src="./support/logo@2x.png" width="300" />
  <br/>
  <br/>
  <p>
    The fastest, most reliable, Redis-based queue for Node. <br/>
    Carefully written for rock solid stability and atomicity.
  </p>
  <br/>
  <p>
    <a href="#-sponsors-"><strong>Sponsors</strong></a> ·
    <a href="#bull-features"><strong>Features</strong></a> ·
    <a href="#uis"><strong>UIs</strong></a> ·
    <a href="#install"><strong>Install</strong></a> ·
    <a href="#quick-guide"><strong>Quick Guide</strong></a> ·
    <a href="#documentation"><strong>Documentation</strong></a>
  </p>
  <p>Check the new <a href="https://optimalbits.github.io/bull/"><strong>Guide!</strong></p>
  <br/>
  <p>
    <a href="https://gitter.im/OptimalBits/bull">
      <img src="https://badges.gitter.im/Join%20Chat.svg"/>
    </a>
    <a href="https://join.slack.com/t/bullmq/shared_invite/zt-1nbtpk6mv-TItWpF9jf3k4yrCaS0PPZA">
      <img src="https://img.shields.io/badge/Slack-4A154B"/>
    </a>
    <a href="http://badge.fury.io/js/bull">
      <img src="https://badge.fury.io/js/bull.svg"/>
    </a>
    <a href="https://coveralls.io/github/OptimalBits/bull?branch=master">
      <img src="https://coveralls.io/repos/github/OptimalBits/bull/badge.svg?branch=master"/>
    </a>
    <a href="http://isitmaintained.com/project/OptimalBits/bull">
      <img src="http://isitmaintained.com/badge/open/optimalbits/bull.svg"/>
    </a>
    <a href="http://isitmaintained.com/project/OptimalBits/bull">
      <img src="http://isitmaintained.com/badge/resolution/optimalbits/bull.svg"/>
    </a>
        <a href="https://twitter.com/manast">
      <img src="https://img.shields.io/twitter/follow/manast?label=Stay%20updated&style=social"/>
    </a>
  </p>
</div>

### 🚀 Sponsors 🚀

<table cellspacing="0" cellpadding="0" border="0">
  <tr>
    <td>
      <a href="https://www.dragonflydb.io/">
        <img src="https://raw.githubusercontent.com/dragonflydb/dragonfly/main/.github/images/logo-full.svg" width=550 alt="Dragonfly" />
      </a>
    </td>
    <td>
      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 <a href="https://www.dragonflydb.io/docs/integrations/bullmq">here</a> on how to use it with BullMQ.
    </td>
  </tr>
</table>

### 📻 News and updates

Bull is currently in maintenance mode, we are only fixing bugs. For new features check [BullMQ](https://github.com/taskforcesh/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](http://twitter.com/manast) 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:

<table cellspacing="0" cellpadding="0">
  <tr>
    <td valign="center">
      <a href="https://github.com/atlassian/github-for-jira">
        <img
          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"
          width="150"
          alt="Atlassian"
      /></a>
    </td>
    <td valign="center">
      <a href="https://github.com/Autodesk">
        <img
          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"
          width="150"
          alt="Autodesk"
      /></a>
    </td>
    <td valign="center">
      <a href="https://github.com/common-voice/common-voice">
        <img
          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"
          width="150"
          alt="Mozilla"
      /></a>
    </td>
    <td valign="center">
      <a href="https://github.com/nestjs/bull">
        <img
          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"
          width="150"
          alt="Nest"
      /></a>
    </td>
    <td valign="center">
      <a href="https://github.com/salesforce/refocus">
        <img
          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"
          width="100"
          alt="Salesforce"
      /></a>
    </td>

  </tr>
</table>

---

---

### Official FrontEnd

[<img src="http://taskforce.sh/assets/logo_square.png" width="100" alt="Taskforce.sh, Inc" style="padding: 100px"/>](https://taskforce.sh)

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](https://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](https://github.com/OptimalBits/bull/blob/develop/PATTERNS.md#returning-job-completions) in the meantime).
- [ ] Parent-child jobs relationships.

---

### UIs

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

**BullMQ**

- [Taskforce](https://taskforce.sh)

**Bull v3**

- [Taskforce](https://taskforce.sh)
- [bull-board](https://github.com/vcapretz/bull-board)
- [bull-repl](https://github.com/darky/bull-repl)
- [bull-monitor](https://github.com/s-r-x/bull-monitor)
- [Monitoro](https://github.com/AbhilashJN/monitoro)

**Bull <= v2**

- [Matador](https://github.com/ShaneK/Matador)
- [react-bull](https://github.com/kfatehi/react-bull)
- [Toureiro](https://github.com/Epharmix/Toureiro)

---

### Monitoring & Alerting

- With Prometheus [Bull Queue Exporter](https://github.com/UpHabit/bull_exporter)

---

### Feature Comparison

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

| Feature                   |   [BullMQ-Pro](https://bullmq.io/#bullmq-pro)    |     [BullMQ](https://bullmq.io)      |      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

```bash
npm install bull --save
```
or

```bash
yarn add bull
```

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


### Typescript Definitions

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

Definitions are currently maintained in the [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/bull) repo.


## Contributing

We welcome all types of contributions, either code fixes, new features or doc improvements.
Code formatting is enforced by [prettier](https://prettier.io/).
For commits please follow conventional [commits convention](https://www.conventionalcommits.org/en/v1.0.0-beta.2/).
All code must pass lint rules and test suites before it can be merged into develop.

---

### Quick Guide

#### Basic Usage
```js
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:

```javascript
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:
```js
// processor.js
module.exports = function (job) {
  // Do some heavy work

  return Promise.resolve(result);
}
```

And define the processor like this:

```js
// 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:

```js
  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](https://crontab.cronhub.io)

#### Pause / Resume

A queue can be paused and resumed globally (pass `true` to pause processing for
just this worker):
```js
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...
```js
.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](./REFERENCE.md#events)

#### Queues performance

Queues are cheap, so if you need many of them just create new ones with different
names:
```javascript
const userJohn = new Queue('john');
const userLisa = new Queue('lisa');
.
.
.
```

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

#### 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:
```js
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](https://optimalbits.github.io/bull/) — Your starting point for developing with Bull.
- [Reference](./REFERENCE.md) — Reference document with all objects and methods available.
- [Patterns](./PATTERNS.md) — a set of examples for common patterns.
- [License](./LICENSE.md) — 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](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).

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


================================================
FILE: REFERENCE.md
================================================
# Reference

- [Queue](#queue)

  - [Queue#process](#queueprocess)
  - [Queue#add](#queueadd)
  - [Queue#addBulk](#queueaddBulk)
  - [Queue#pause](#queuepause)
  - [Queue#isPaused](#queueispaused)
  - [Queue#resume](#queueresume)
  - [Queue#whenCurrentJobsFinished](#queuewhencurrentjobsfinished)
  - [Queue#count](#queuecount)
  - [Queue#removeJobs](#queueremovejobs)
  - [Queue#empty](#queueempty)
  - [Queue#clean](#queueclean)
  - [Queue#obliterate](#queueobliterate)
  - [Queue#close](#queueclose)
  - [Queue#getJob](#queuegetjob)
  - [Queue#getJobs](#queuegetjobs)
  - [Queue#getJobLogs](#queuegetjoblogs)
  - [Queue#getRepeatableJobs](#queuegetrepeatablejobs)
  - [Queue#removeRepeatable](#queueremoverepeatable)
  - [Queue#removeRepeatableByKey](#queueremoverepeatablebykey)
  - [Queue#getJobCounts](#queuegetjobcounts)
  - [Queue#getCompletedCount](#queuegetcompletedcount)
  - [Queue#getFailedCount](#queuegetfailedcount)
  - [Queue#getDelayedCount](#queuegetdelayedcount)
  - [Queue#getActiveCount](#queuegetactivecount)
  - [Queue#getWaitingCount](#queuegetwaitingcount)
  - [Queue#getPausedCount](#queuegetpausedcount)
  - [Queue#getWaiting](#queuegetwaiting)
  - [Queue#getActive](#queuegetactive)
  - [Queue#getDelayed](#queuegetdelayed)
  - [Queue#getCompleted](#queuegetcompleted)
  - [Queue#getFailed](#queuegetfailed)
  - [Queue#getWorkers](#queuegetworkers)
  - [Queue#getMetrics](#queuegetmetrics)

- [Job](#job)

  - [Job#progress](#jobprogress)
  - [Job#log](#joblog)
  - [Job#getState](#jobgetstate)
  - [Job#update](#jobupdate)
  - [Job#remove](#jobremove)
  - [Job#retry](#jobretry)
  - [Job#discard](#jobdiscard)
  - [Job#promote](#jobpromote)
  - [Job#finished](#jobfinished)
  - [Job#moveToCompleted](#jobmovetocompleted)
  - [Job#moveToFailed](#jobmovetofailed)
  - [Job#lockKey](#joblockkey)
  - [Job#releaseLock](#jobreleaselock)
  - [Job#takeLock](#jobtakelock)
  - [Job#extendLock](#jobextendlock)

- [Events](#events)
  - [Global events](#global-events)

## Queue

```ts
Queue(queueName: string, url?: string, opts?: QueueOptions): Queue
```

This is the Queue constructor. It creates a new Queue that is persisted in
Redis. Everytime the same queue is instantiated it tries to process all the
old jobs that may exist from a previous unfinished session.

The optional `url` argument, allows to specify a redis connection string such as for example:
`redis://mypassword@myredis.server.com:1234`

```typescript
interface QueueOptions {
  createClient?: (type: 'client' | 'subscriber' | 'bclient', config?: Redis.RedisOptions) => Redis.Redis | Redis.Cluster;
  limiter?: RateLimiter;
  redis?: RedisOpts;
  prefix?: string = 'bull'; // prefix for all queue keys.
  metrics?: MetricsOpts; // Configure metrics
  defaultJobOptions?: JobOpts;
  settings?: AdvancedSettings;
}
```

```typescript
interface MetricsOpts {
    maxDataPoints?: number; //  Max number of data points to collect, granularity is fixed at one minute.
}
```

```typescript
interface RateLimiter {
  max: number; // Max number of jobs processed
  duration: number; // per duration in milliseconds
  bounceBack?: boolean = false; // When jobs get rate limited, they stay in the waiting queue and are not moved to the delayed queue
  groupKey?: string; // allows grouping of jobs with the specified key from the data object passed to the Queue#add (ex. "network.handle")
}
```

`RedisOpts` are passed directly to ioredis constructor, check [ioredis](https://github.com/luin/ioredis/blob/master/API.md)
for details. We document here just the most important ones.

```typescript
interface RedisOpts {
  port?: number = 6379;
  host?: string = localhost;
  db?: number = 0;
  password?: string;
}
```

```typescript
interface AdvancedSettings {
  lockDuration: number = 30000; // Key expiration time for job locks.
  lockRenewTime: number = 15000; // Interval on which to acquire the job lock
  stalledInterval: number = 30000; // How often check for stalled jobs (use 0 for never checking).
  maxStalledCount: number = 1; // Max amount of times a stalled job will be re-processed.
  guardInterval: number = 5000; // Poll interval for delayed jobs and added jobs.
  retryProcessDelay: number = 5000; // delay before processing next job in case of internal error.
  backoffStrategies: {}; // A set of custom backoff strategies keyed by name.
  drainDelay: number = 5; // A timeout for when the queue is in drained state (empty waiting for jobs).
  isSharedChildPool: boolean = false; // enables multiple queues on the same instance of child pool to share the same instance.
}
```

#### Custom or Shared IORedis Connections

`createClient` is passed a `type` to specify the type of connection that Bull is trying to create, and some options that `bull` would like to set for that connection.

You can merge the provided options with some of your own and create an `ioredis` connection.

When type is `client` or `subscriber` you can return the same connection for multiple queues, which can reduce the number of connections you open to the redis server.  Bull
does not close or disconnect these connections when queues are closed, so if you need to have your app do a graceful shutdown, you will need to keep references to these
Redis connections somewhere and disconnect them after you shut down all the queues.

The `bclient` connection however is a "blocking client" and is used to wait for new jobs on a single queue at a time.  For this reason it cannot be shared and a
new connection should be returned each time.

#### Advanced Settings

**Warning:** Do not override these advanced settings unless you understand the internals of the queue.

`lockDuration`: Time in milliseconds to acquire the job lock. Set this to a higher value if you find that your jobs are being stalled because your job processor is CPU-intensive and blocking the event loop (see note below about stalled jobs). Set this to a lower value if your jobs are extremely time-sensitive and it might be OK if they get double-processed (due to them be falsly considered stalled).

`lockRenewTime`: Interval in milliseconds on which to acquire the job lock. It is set to `lockDuration / 2` by default to give enough buffer to renew the lock each time before the job lock expires. It should never be set to a value larger than `lockDuration`. Set this to a lower value if you're finding that jobs are becoming stalled due to a CPU-intensive job processor function. Generally you shouldn't change this though.

`stalledInterval`: Interval in milliseconds on which each worker will check for stalled jobs (i.e. unlocked jobs in the `active` state). See note below about stalled jobs. Set this to a lower value if your jobs are extremely time-sensitive. Set this to a higher value if your Redis CPU usage is high as this check can be expensive. Note that because each worker runs this on its own interval and checks the entire queue, the stalled job actually run much more frequently than this value would imply.

`maxStalledCount`: The maximum number of times a job can be restarted before it will be permamently failed with the error `job stalled more than allowable limit`. This is set to a default of `1` with the assumption that stalled jobs should be very rare (only due to process crashes) and you want to be on the safer side of not restarting jobs. Set this higher if stalled jobs are common (e.g. processes crash a lot) and it's generally OK to double process jobs.

`guardInterval`: Interval in milliseconds on which the delayed job watchdog will run. When running multiple concurrent workers with delayed tasks, the default value of `guardInterval` will cause spikes on network bandwidth, cpu usage and memory usage. Each concurrent worker will run the delayed job watchdog. In this case set this value to something much higher, e.g. `guardInterval = numberOfWorkers*5000`. Set to a lower value if your Redis connection is unstable and delayed jobs aren't being processed in time.

`retryProcessDelay`: Time in milliseconds in which to wait before trying to process jobs, in case of a Redis error. Set to a lower value on an unstable Redis connection.

`backoffStrategies`: An object containing custom backoff strategies. The key in the object is the name of the strategy and the value is a function that should return the delay in milliseconds. For a full example see [Patterns](./PATTERNS.md#custom-backoff-strategy).

`drainDelay`: A timeout for when the queue is in `drained` state (empty waiting for jobs). It is used when calling `queue.getNextJob()`, which will pass it to `.brpoplpush` on the Redis client.

```js
backoffStrategies: {
  jitter: function () {
    return 5000 + Math.random() * 500;
  }
}
```

---

### Queue#process

```ts
/**
 * Consider these as overloaded functions. Since method overloading doesn't exist in JavaScript,
 * Bull recognizes the desired function call by checking the parameters' types.
 * Make sure you comply with one of the below defined patterns.
 *
 * Note: Concurrency defaults to 1 if not specified.
 */
process(processor: ((job, done?) => Promise<any>) | string)
process(concurrency: number, processor: ((job, done?) => Promise<any>) | string)
process(name: string, processor: ((job, done?) => Promise<any>) | string)
process(name: string, concurrency: number, processor: ((job, done?) => Promise<any>) | string)
```

Defines a processing function for the jobs in a given Queue.

The callback is called every time a job is placed in the queue. It is passed an instance of the job as first argument.

If the callback signature contains the second optional `done` argument, the callback will be passed a `done` callback to be called after the job has been completed. The `done` callback can be called with an Error instance, to signal that the job did not complete successfully, or with a result as second argument (e.g.: `done(null, result);`) when the job is successful. Errors will be passed as a second argument to the "failed" event;
results, as a second argument to the "completed" event.

If, however, the callback signature does not contain the `done` argument, a promise must be returned to signal job completion. If the promise is rejected, the error will be passed as a second argument to the "failed" event.
If it is resolved, its value will be the "completed" event's second argument.

You can specify a `concurrency` argument. Bull will then call your handler in parallel respecting this maximum value.

A process function can also be declared as a separate process. This will make a better use of the available CPU cores
and run the jobs in parallel. This is a perfect way to run blocking code. Just specify an absolute path to a processor module.
i.e. a file exporting the process function like this:

```js
// my-processor.js
module.exports = function (job) {
  // do some job

  return value;
};
```

You can return a value or a promise to signal that the job has been completed.

A `name` argument can be provided so that multiple process functions can be defined per queue. A named process will only process jobs that matches the given name. However, if you define multiple named process functions in one Queue, the defined concurrency for each process function stacks up for the Queue. See the following examples:

```js
/***
 * For each named processor, concurrency stacks up, so any of these three process functions
 * can run with a concurrency of 125. To avoid this behaviour you need to create an own queue
 * for each process function.
 */
const loadBalancerQueue = new Queue('loadbalancer');
loadBalancerQueue.process('requestProfile', 100, requestProfile);
loadBalancerQueue.process('sendEmail', 25, sendEmail);
loadBalancerQueue.process('sendInvitation', 0, sendInvite);

const profileQueue = new Queue('profile');
// Max concurrency for requestProfile is 100
profileQueue.process('requestProfile', 100, requestProfile);

const emailQueue = new Queue('email');
// Max concurrency for sendEmail is 25
emailQueue.process('sendEmail', 25, sendEmail);
```

Specifying `*` as the process name will make it the default processor for all named jobs.
It is frequently used to process all named jobs from one process function:

```js
const differentJobsQueue = new Queue('differentJobsQueue');
differentJobsQueue.process('*', processFunction);
differentJobsQueue.add('jobA', data, opts);
differentJobsQueue.add('jobB', data, opts);
```

**Note:** in order to determine whether job completion is signaled by
returning a promise or calling the `done` callback, Bull looks at
the length property of the callback you pass to it.
So watch out, as the following won't work:

```js
// THIS WON'T WORK!!
queue.process(function (job, done) {
  // Oops! done callback here!
  return Promise.resolve();
});
```

This, however, will:

```js
queue.process(function (job) {
  // No done callback here :)
  return Promise.resolve();
});
```

---

### Queue#add

```ts
add(name?: string, data: object, opts?: JobOpts): Promise<Job>
```

Creates a new job and adds it to the queue. If the queue is empty the job will be executed directly, otherwise it will be placed in the queue and executed as soon as possible.

An optional name can be added, so that only process functions defined for that name (also called job type) will process the job.

**Note:**
You need to define _processors_ for all the named jobs that you add to your queue or the queue will complain that you are missing a processor for the given job, unless you use the `*` as job name when defining the processor.

**Note:**
Considering all jobs in a finished state (`failed` or `completed`) are stored in Redis, depending on the number of jobs running and your Redis setup, you might want to setup a default maximum number of jobs kept, using the `removeOnComplete` and `removeOnFail` options when creating a queue so Redis does not end up running out of memory.

```typescript
interface JobOpts {
  priority: number; // Optional priority value. ranges from 1 (highest priority) to MAX_INT  (lowest priority). Note that
  // using priorities has a slight impact on performance, so do not use it if not required.

  delay: number; // An amount of milliseconds to wait until this job can be processed. Note that for accurate delays, both
  // server and clients should have their clocks synchronized. [optional].

  attempts: number; // The total number of attempts to try the job until it completes.

  repeat: RepeatOpts; // Repeat job according to a cron specification, see below for details.

  backoff: number | BackoffOpts; // Backoff setting for automatic retries if the job fails, default strategy: `fixed`.
  // Needs `attempts` to be set.

  lifo: boolean; // if true, adds the job to the right of the queue instead of the left (default false)
  timeout: number; // The number of milliseconds after which the job should fail with a timeout error [optional]

  jobId: number | string; // Override the job ID - by default, the job ID is a unique
  // integer, but you can use this setting to override it.
  // If you use this option, it is up to you to ensure the
  // jobId is unique. If you attempt to add a job with an id that
  // already exists, it will not be added (see caveat below about repeatable jobs).

  removeOnComplete: boolean | number | KeepJobs; // If true, removes the job when it successfully
  // completes. A number specified the amount of jobs to keep. Default behavior is to keep the job in the completed set.
  // See KeepJobs if using that interface instead.

  removeOnFail: boolean | number | KeepJobs; // If true, removes the job when it fails after all attempts. A number specified the amount of jobs to keep, see KeepJobs if using that interface instead.
  // Default behavior is to keep the job in the failed set.
  stackTraceLimit: number; // Limits the amount of stack trace lines that will be recorded in the stacktrace.
}
```

#### KeepJobs Options
```typescript
/**
 * KeepJobs
 *
 * Specify which jobs to keep after finishing. If both age and count are
 * specified, then the jobs kept will be the ones that satisfies both
 * properties.
 */
export interface KeepJobs {
  /**
   * Maximum age in *seconds* for job to be kept.
   */
  age?: number;

  /**
   * Maximum count of jobs to be kept.
   */
  count?: number;
}
```

---

#### Timeout Implementation

It is important to note that jobs are _not_ proactively stopped after the given `timeout`. The job is marked as failed
and the job's promise is rejected, but Bull has no way to stop the processor function externally.

If you need a job to stop processing after it times out, here are a couple suggestions:
 - Have the job itself periodically check `job.getStatus()`, and exit if the status becomes `'failed'`
 - Implement the job as a _cancelable promise_. If the processor's promise has a `cancel()` method, it will
   be called when a job times out, and the job can respond accordingly. (Note: currently this only works for
   native Promises, see [#2203](https://github.com/OptimalBits/bull/issues/2203)
 - If you have a way to externally stop a job, add a listener for the `failed` event and do so there.

#### Repeated Job Details
```typescript
interface RepeatOpts {
  cron?: string; // Cron string
  tz?: string; // Timezone
  startDate?: Date | string | number; // Start date when the repeat job should start repeating (only with cron).
  endDate?: Date | string | number; // End date when the repeat job should stop repeating.
  limit?: number; // Number of times the job should repeat at max.
  every?: number; // Repeat every millis (cron setting cannot be used together with this setting.)
  count?: number; // The start value for the repeat iteration count.
  readonly key: string; // The key for the repeatable job metadata in Redis.
}
```

Adding a job with the `repeat` option set will actually do two things immediately: create a Repeatable Job configuration,
and schedule a regular delayed job for the job's first run. This first run will be scheduled "on the hour", that is if you create
a job that repeats every 15 minutes at 4:07, the job will first run at 4:15, then 4:30, and so on. If `startDate` is set, the job
will not run before `startDate`, but will still run "on the hour". In the previous example, if `startDate` was set for some day at
6:05, the same day, the first job would run on that day at 6:15.

The cron expression uses the [cron-parser](https://github.com/harrisiirak/cron-parser) library, see their docs for more details.

The Repeatable Job configuration is not a job, so it will not show up in methods like `getJobs()`. To manage Repeatable Job
configurations, use [`getRepeatableJobs()`](#queuegetrepeatablejobs) and similar. This also means repeated jobs do **not**
participate in evaluating `jobId` uniqueness - that is, a non-repeatable job can have the same `jobId` as a Repeatable Job
configuration, and two Repeatable Job configurations can have the same `jobId` as long as they have different repeat options.

That is, the following code will result in three jobs being created (one immediate and two delayed):
```ts
await queue.add({}, { jobId: 'example', repeat: { every: 5 * 1000 } })
await queue.add({}, { jobId: 'example', repeat: { every: 5 * 1000 } }) // Will not be created, same repeat configuration
await queue.add({}, { jobId: 'example', repeat: { every: 10 * 1000 } }) // Will be created, different repeat configuration
await queue.add({}, { jobId: 'example' }) // Will be created, no regular job with this id
await queue.add({}, { jobId: 'example' }) // Will not be created, conflicts with previous regular job
```

#### Backoff Options
```typescript
interface BackoffOpts {
  type: string; // Backoff type, which can be either `fixed` or `exponential`. A custom backoff strategy can also be specified in `backoffStrategies` on the queue settings.
  delay: number; // Backoff delay, in milliseconds.
  options?: any; // Options for custom strategies
}
```

---

### Queue#addBulk

```ts
addBulk(jobs: { name?: string, data: object, opts?: JobOpts }[]): Promise<Job[]>
```

Creates array of jobs and adds them to the queue. They follow the same signature as [Queue#add](#queueadd).

---

### Queue#pause

```ts
pause(isLocal?: boolean, doNotWaitActive?: boolean): Promise
```

Returns a promise that resolves when the queue is paused. A paused queue will not process new jobs until resumed, but current jobs being processed will continue until they are finalized. The pause can be either global or local. If global, all workers in all queue instances for a given queue will be paused. If local, just this worker will stop processing new jobs after the current lock expires. This can be useful to stop a worker from taking new jobs prior to shutting down.

If `doNotWaitActive` is `true`, `pause` will _not_ wait for any active jobs to finish before resolving. Otherwise, `pause` _will_ wait for active jobs to finish. See [Queue#whenCurrentJobsFinished](#queuewhencurrentjobsfinished) for more information.

Pausing a queue that is already paused does nothing.

---

### Queue#isPaused

```ts
isPaused(isLocal?: boolean): Promise<boolean>
```

Checks if the queue is paused. Pass true if you need to know if this particular instance is paused.

---

### Queue#resume

```ts
resume(isLocal?: boolean): Promise
```

Returns a promise that resolves when the queue is resumed after being paused. The resume can be either local or global. If global, all workers in all queue instances for a given queue will be resumed. If local, only this worker will be resumed. Note that resuming a queue globally will _not_ resume workers that have been paused locally; for those, `resume(true)` must be called directly on their instances.

Resuming a queue that is not paused does nothing.

---

### Queue#whenCurrentJobsFinished

```ts
whenCurrentJobsFinished(): Promise<Void>
```

Returns a promise that resolves when all jobs currently being processed by this worker have finished.

---

### Queue#count

```ts
count(): Promise<number>
```

Returns a promise that returns the number of jobs in the queue, waiting or delayed. Since there may be other processes adding or processing jobs, this value may be true only for a very small amount of time.

---

### Queue#removeJobs

```ts
removeJobs(pattern: string): Promise<void>
```

Removes all the jobs which jobId matches the given pattern. The pattern must follow redis glob-style pattern [syntax](https://redis.io/commands/keys)

Example:

```js
myQueue.removeJobs('?oo*').then(function () {
  console.log('done removing jobs');
});
```

Will remove jobs with ids such as: "boo", "foofighter", etc.

Note: This method does not affect Repeatable Job configurations, instead use [`removeRepeatable()`](#queueremoverepeatable) or [`removeRepeatableByKey()`](#queueremoverepeatablebykey)

---

### Queue#empty

```ts
empty(): Promise
```

Drains a queue deleting all the *input* lists and associated jobs.

Note: This function only removes the jobs that are *waiting* to be processed by the queue or *delayed*.
Jobs in other states (active, failed, completed) and Repeatable Job configurations will remain, and
repeatable jobs will continue to be created on schedule.

To remove other job statuses, use [`clean()`](#queueclean), and to remove everything including Repeatable Job
configurations, use [`obliterate()`](#queueobliterate).

---

### Queue#close

```ts
close(doNotWaitJobs?: boolean): Promise
```

Closes the underlying Redis client. Use this to perform a graceful shutdown.

```js
const Queue = require('bull');
const queue = Queue('example');

const after100 = _.after(100, function () {
  queue.close().then(function () {
    console.log('done');
  });
});

queue.on('completed', after100);
```

`close` can be called from anywhere, with one caveat: if called
from within a job handler the queue won't close until _after_
the job has been processed, so the following won't work:

```js
queue.process(function (job, jobDone) {
  handle(job);
  queue.close().then(jobDone);
});
```

Instead, do this:

```js
queue.process(function (job, jobDone) {
  handle(job);
  queue.close();
  jobDone();
});
```

Or this:

```js
queue.process(function (job) {
  queue.close();
  return handle(job).then(...);
});
```

---

### Queue#getJob

```ts
getJob(jobId: string): Promise<Job>
```

Returns a promise that will return the job instance associated with the `jobId`
parameter. If the specified job cannot be located, the promise will be resolved to `null`.

Note: This method does not return Repeatable Job configurations, to do so see [`getRepeatableJobs()`](#queuegetrepeatablejobs)

---

### Queue#getJobs

```ts
getJobs(types: JobStatus[], start?: number, end?: number, asc?: boolean): Promise<Job[]>
```

Returns a promise that will return an array of job instances of the given job statuses. Optional parameters for range and ordering are provided.

Note: The `start` and `end` options are applied **per job statuses**. For example, if there are 10 jobs in state `completed` and 10 jobs in state `active`, `getJobs(['completed', 'active'], 0, 4)` will yield an array with 10 entries, representing the first 5 completed jobs (0 - 4) and the first 5 active jobs (0 - 4).

This method does not return Repeatable Job configurations, to do so see [`getRepeatableJobs()`](#queuegetrepeatablejobs)

---

### Queue#getJobLogs

```ts
getJobLogs(jobId: string, start?: number, end?: number): Promise<{
  logs: string[],
  count: number
}>
```

Returns a object with the logs according to the start and end arguments. The returned count
value is the total amount of logs, useful for implementing pagination.

---

### Queue#getRepeatableJobs

```ts
getRepeatableJobs(start?: number, end?: number, asc?: boolean): Promise<{
          key: string,
          name: string,
          id: number | string,
          endDate: Date,
          tz: string,
          cron: string,
          every: number,
          next: number
        }[]>
```

Returns a promise that will return an array of Repeatable Job configurations. Optional parameters for range and ordering are provided.

---

### Queue#removeRepeatable

```ts
removeRepeatable(name?: string, repeat: RepeatOpts): Promise<void>
```

Removes a given Repeatable Job configuration. The RepeatOpts needs to be the same as the ones used
for the job when it was added.

---

---

### Queue#removeRepeatableByKey

```ts
removeRepeatableByKey(key: string): Promise<void>
```

Removes a given Repeatable Job configuration by its key so that no more repeatable jobs will be processed for this
particular configuration.

There are currently two ways to get the "key" of a repeatable job.

When first creating the job, `queue.add()` will return a job object with the key for that job, which you can store for later use:
```ts
const job = await queue.add('remove', { example: 'data' }, { repeat: { every: 1000 } });
// store job.opts.repeat.key somewhere...
const repeatableKey = job.opts.repeat.key;

// ...then later...
await queue.removeRepeatableByKey(repeatableKey);
```

Otherwise, you can list all repeatable jobs with [`getRepeatableJobs()`](#queuegetrepeatablejobs), find the job you want to remove in the list, and use the key there to remove it:
```ts
await queue.add('remove', { example: 'data' }, { jobId: 'findMe', repeat: { every: 1000 } })

// ... then later ...
const repeatableJobs = await queue.getRepeatableJobs()
const foundJob = repeatableJobs.find(job => job.id === 'findMe')
await queue.removeRepeatableByKey(foundJob.key)
```
---

### Queue#getJobCounts

```ts
getJobCounts() : Promise<JobCounts>
```

Returns a promise that will return the job counts for the given queue.

```typescript
{
  interface JobCounts {
    waiting: number,
    active: number,
    completed: number,
    failed: number,
    delayed: number
  }
}
```

---

### Queue#getCompletedCount

```ts
getCompletedCount() : Promise<number>
```

Returns a promise that will return the completed job counts for the given queue.

---

### Queue#getFailedCount

```ts
getFailedCount() : Promise<number>
```

Returns a promise that will return the failed job counts for the given queue.

---

### Queue#getDelayedCount

```ts
getDelayedCount() : Promise<number>
```

Returns a promise that will return the delayed job counts for the given queue.

---

### Queue#getActiveCount

```ts
getActiveCount() : Promise<number>
```

Returns a promise that will return the active job counts for the given queue.

---

### Queue#getWaitingCount

```ts
getWaitingCount() : Promise<number>
```

Returns a promise that will return the waiting job counts for the given queue.

---

### Queue#getPausedCount

*DEPRECATED* Since only the queue can be paused, getWaitingCount gives the same
result.

```ts
getPausedCount() : Promise<number>
```

Returns a promise that will return the paused job counts for the given queue.

---

### Getters

The following methods are used to get the jobs that are in certain states.

The GetterOpts can be used for configure some aspects from the getters.

```ts
interface GetterOpts
  excludeData: boolean; // Exclude the data field of the jobs.
```

### Queue#getWaiting

```ts
getWaiting(start?: number, end?: number, opts?: GetterOpts) : Promise<Array<Job>>
```

Returns a promise that will return an array with the waiting jobs between start and end.

---

### Queue#getActive

```ts
getActive(start?: number, end?: number, opts?: GetterOpts) : Promise<Array<Job>>
```

Returns a promise that will return an array with the active jobs between start and end.

---

### Queue#getDelayed

```ts
getDelayed(start?: number, end?: number, opts?: GetterOpts) : Promise<Array<Job>>
```

Returns a promise that will return an array with the delayed jobs between start and end.

---

### Queue#getCompleted

```ts
getCompleted(start?: number, end?: number, opts?: GetterOpts) : Promise<Array<Job>>
```

Returns a promise that will return an array with the completed jobs between start and end.

---

### Queue#getFailed

```ts
getFailed(start?: number, end?: number, opts?: GetterOpts) : Promise<Array<Job>>
```

Returns a promise that will return an array with the failed jobs between start and end.

---

### Queue#getWorkers

```ts
getWorkers() : Promise<Array<Object>>
```

Returns a promise that will resolve to an array workers currently listening or processing jobs.
The object includes the same fields as [Redis CLIENT LIST](https://redis.io/commands/client-list) command.

---

### Queue#getMetrics

```ts
getMetrics(type: 'completed' | 'failed', start = 0, end = -1) : Promise<{
  meta: {
    count: number;
    prevTS: number;
    prevCount: number;
  };
  data: number[];
  count: number;
}>
```

Returns a promise that resolves to a Metrics object.

---

### Queue#clean

```ts
clean(grace: number, status?: string, limit?: number): Promise<number[]>
```

Tells the queue remove jobs of a specific type created outside of a grace period.

#### Example

```js
queue.on('cleaned', function (jobs, type) {
  console.log('Cleaned %s %s jobs', jobs.length, type);
});

//cleans all jobs that completed over 5 seconds ago.
await queue.clean(5000);
//clean all jobs that failed over 10 seconds ago.
await queue.clean(10000, 'failed');
```

### Queue#obliterate

```ts
obliterate(ops?: { force: boolean}): Promise<void>
```

Completely removes a queue with all its data.
In order to obliterate a queue there cannot be active jobs, but this
behaviour can be overrided with the "force" option.

Note: since this operation can be quite long in duration depending on how
many jobs there are in the queue, it is not performed atomically, instead
is performed iterativelly. However the queue is always paused during this process,
if the queue gets unpaused during the obliteration by another script, the call
will fail with the removed items it managed to remove until the failure.

#### Example

```js
// Removes everything but only if there are no active jobs
await queue.obliterate();

await queue.obliterate({ force: true });
```

---

## Job

A job includes all data needed to perform its execution, as well as the progress method needed to update its progress.

The most important property for the user is `Job#data` that includes the object that was passed to [`Queue#add`](#queueadd), and that is normally used to perform the job.

Other useful job properties:
* `job.attemptsMade`: number of failed attempts.
* `job.finishedOn`: Unix Timestamp, when job is completed or finally failed after all attempts.

### Job#progress

```ts
progress(progress?: number | object): Promise
```

Updates a job progress if called with an argument.
Return a promise resolving to the current job's progress if called without argument.

#### Arguments

```js
  progress: number; Job progress number or any serializable object representing progress or similar.
```

---

### Job#log

```ts
log(row: string): Promise
```

Adds a log row to this job specific job. Logs can be retrieved using [Queue#getJobLogs](#queuegetjoblogs).

---

### Job#getState

```ts
getState(): Promise
```

Returns a promise resolving to the current job's status (completed, failed, delayed etc.). Possible returns are: completed, failed, delayed, active, waiting, paused, stuck or null.

Please take note that the implementation of this method is not very efficient, nor is it atomic. If your queue does have a very large quantity of jobs, you may want to avoid using this method.

---

### Job#update

```ts
update(data: object): Promise
```

Updated a job data field with the give data object.

---

### Job#remove

```ts
remove(): Promise
```

Removes a job from the queue and from any lists it may be included in.

---

### Job#retry

```ts
retry(): Promise
```

Re-run a job that has failed. Returns a promise that resolves when the job is scheduled for retry.

---

### Job#discard

```ts
discard(): Promise
```

Ensure this job is never ran again even if `attemptsMade` is less than `job.attempts`.

---

### Job#promote

```ts
promote(): Promise
```

Promotes a job that is currently "delayed" to the "waiting" state and executed as soon as possible.

---

### Job#finished

```ts
finished(): Promise
```

Returns a promise that resolves or rejects when the job completes or fails.

---

### Job#moveToCompleted

```ts
moveToCompleted(returnValue: any, ignoreLock: boolean, notFetch?: boolean): Promise<string[Jobdata, JobId] | null>
```

Moves a job to the `completed` queue. Pulls a job from 'waiting' to 'active' and returns a tuple containing the next jobs data and id. If no job is in the `waiting` queue, returns null. Set `notFetch` to true to avoid prefetching the next job in the queue.

---

### Job#moveToFailed

```ts
moveToFailed(errorInfo:{ message: string; }, ignoreLock?:boolean): Promise<string[Jobdata, JobId] | null>
```

Moves a job to the `failed` queue. Pulls a job from 'waiting' to 'active' and returns a tuple containing the next jobs data and id. If no job is in the `waiting` queue, returns null.

---

### Job#lockKey

```ts
lockKey(): string
```

Return a unique key representing a lock for this Job.

---

### Job#releaseLock

```ts
releaseLock(): Promise<void>
```

Releases the lock on the job. Only locks owned by the queue instance can be released.

---

### Job#takeLock

```ts
takeLock(): Promise<number | false>
```

Takes a lock for this job so that no other queue worker can process it at the same time.

---

### Job#extendLock

```ts
extendLock(duration: number): Promise<number>
```

Extend the lock for this job. The `duration` parameter specifies the lock duration in milliseconds. It will return '1' on success and '0' on failure.

---
## Events

A queue emits also some useful events:

```js
.on('error', function (error) {
  // An error occured.
})

.on('waiting', function (jobId) {
  // A Job is waiting to be processed as soon as a worker is idling.
});

.on('active', function (job, jobPromise) {
  // A job has started. You can use `jobPromise.cancel()`` to abort it.
})

.on('stalled', function (job) {
  // A job has been marked as stalled. This is useful for debugging job
  // workers that crash or pause the event loop.
})

.on('lock-extension-failed', function (job, err) {
  // A job failed to extend lock. This will be useful to debug redis
  // connection issues and jobs getting restarted because workers
  // are not able to extend locks.
});

.on('progress', function (job, progress) {
  // A job's progress was updated!
})

.on('completed', function (job, result) {
  // A job successfully completed with a `result`.
})

.on('failed', function (job, err) {
  // A job failed with reason `err`!
})

.on('paused', function () {
  // The queue has been paused.
})

.on('resumed', function (job) {
  // The queue has been resumed.
})

.on('cleaned', function (jobs, type) {
  // Old jobs have been cleaned from the queue. `jobs` is an array of cleaned
  // jobs, and `type` is the type of jobs cleaned.
});

.on('drained', function () {
  // Emitted every time the queue has processed all the waiting jobs (even if there can be some delayed jobs not yet processed)
});

.on('removed', function (job) {
  // A job successfully removed.
});

```

### Global events

Events are local by default — in other words, they only fire on the listeners that are registered on the given worker. If you need to listen to events globally, for example from other servers across redis, just prefix the event with `'global:'`:

```js
// Will listen locally, just to this queue...
queue.on('completed', listener):

// Will listen globally, to instances of this queue...
queue.on('global:completed', listener);
```

When working with global events whose local counterparts pass a `Job` instance to the event listener callback, notice that global events pass the **job's ID** instead.

If you need to access the `Job` instance in a global listener, use [Queue#getJob](#queuegetjob) to retrieve it. However, remember that if `removeOnComplete` is enabled when adding the job, the job will no longer be available after completion. Should you need to both access the job and remove it after completion, you can use [Job#remove](#jobremove) to remove it in the listener.

```js
// Local events pass the job instance...
queue.on('progress', function (job, progress) {
  console.log(`Job ${job.id} is ${progress * 100}% ready!`);
});

queue.on('completed', function (job, result) {
  console.log(`Job ${job.id} completed! Result: ${result}`);
  job.remove();
});

// ...whereas global events only pass the job ID:
queue.on('global:progress', function (jobId, progress) {
  console.log(`Job ${jobId} is ${progress * 100}% ready!`);
});

queue.on('global:completed', function (jobId, result) {
  console.log(`Job ${jobId} completed! Result: ${result}`);
  queue.getJob(jobId).then(function (job) {
    job.remove();
  });
});
```


================================================
FILE: commandTransform.js
================================================
'use strict';
const path = require('path');
const fs = require('fs');
const { argv } = require('process');

const readFile = fs.promises.readFile;
const writeFile = fs.promises.writeFile;
const readdir = fs.promises.readdir;

const loadScripts = async (readDir, writeDir) => {
  const normalizedDir = path.normalize(readDir);

  const files = await readdir(normalizedDir);

  const luaFiles = files.filter(file => path.extname(file) === '.lua');
  const writeFilenamePath = path.normalize(writeDir);

  if (!fs.existsSync(writeFilenamePath)) {
    fs.mkdirSync(writeFilenamePath);
  }

  let indexContent = "'use strict';\nmodule.exports = {\n";

  if (luaFiles.length === 0) {
    /**
     * To prevent unclarified runtime error "updateDelayset is not a function
     * @see https://github.com/OptimalBits/bull/issues/920
     */
    throw new Error('No .lua files found!');
  }

  for (let i = 0; i < luaFiles.length; i++) {
    const completedFilename = path.join(normalizedDir, luaFiles[i]);
    const longName = path.basename(luaFiles[i], '.lua');
    indexContent += `  ["${longName}"]: require('./${longName}'),\n`;

    await loadCommand(completedFilename, longName, writeFilenamePath);
  }
  indexContent += `}\n`;

  await writeFile(path.join(writeFilenamePath, 'index.js'), indexContent);
};

const loadCommand = async (filename, longName, writeFilenamePath) => {
  const filenamePath = path.resolve(filename);

  const content = (await readFile(filenamePath)).toString();

  const [name, num] = longName.split('-');
  const numberOfKeys = num && parseInt(num, 10);

  const newContent = `'use strict';
const content = \`${content}\`;
module.exports = {
  name: '${name}',
  content,${
    numberOfKeys
      ? `
  keys: ${numberOfKeys},`
      : ''
  }
};
`;
  await writeFile(path.join(writeFilenamePath, longName + '.js'), newContent);
};

loadScripts(argv[2], argv[3]);


================================================
FILE: commitlint.config.js
================================================
'use strict';

module.exports = { extends: ['@commitlint/config-conventional'] };


================================================
FILE: docker-compose.yml
================================================
version: '3.2'
services:
  redis:
    image: redis:6.2-alpine
    container_name: cache
    ports:
      - 6379:6379


================================================
FILE: docs/README.md
================================================
<div align="center" style="padding-bottom: 50px;">
  <br/>
  <img src="https://raw.githubusercontent.com/OptimalBits/bull/master/support/logo%402x.png" width="300" />
  <br/>
</div>

# What is Bull?

Bull is a Node library that implements a fast and robust queue system based on [redis](https://redis.io).

Although it is possible to implement queues directly using Redis commands, this library provides an API that takes care of all the low-level details and enriches Redis basic functionality so that more complex use-cases can be handled easily.

If you are new to queues you may wonder why they are needed after all. Queues can solve many different problems in an elegant way, from smoothing out processing peaks to creating robust communication channels between microservices or offloading heavy work from one server to many smaller workers, etc.

# Getting Started

Bull is a public npm package and can be installed using either npm or yarn:

```bash
$ npm install bull --save
```

or

```bash
$ yarn add bull
```

In order to work with Bull, you also need to have a Redis server running. For local development, you can easily install
it using [docker](https://hub.docker.com/_/redis/).

Bull will by default try to connect to a Redis server running on `localhost:6379`

# Simple Queues

A queue is simply created by instantiating a Bull instance:

```js
const myFirstQueue = new Bull('my-first-queue');
```

A queue instance can normally have 3 main different roles: A job producer, a job consumer or/and an events listener.

Although one given instance can be used for the 3 roles, normally the producer and consumer are divided into several instances. A given queue, always referred to by its instantiation name ( `my-first-queue` in the example above ), can have many producers, many consumers, and many listeners. An important aspect is that producers can add jobs to a queue even if there are no consumers available at that moment: queues provide asynchronous communication, which is one of the features that makes them so powerful.

Conversely, you can have one or more workers consuming jobs from the queue, which will consume the jobs in a given order: FIFO (the default), LIFO or according to priorities.

Talking about workers, they can run in the same or different processes, in the same machine, or in a cluster. Redis will act as a common point, and as long as a consumer or producer can connect to Redis, they will be able to co-operate in processing the jobs.

## Producers

A job producer is simply some Node program that adds jobs to a queue, like this:

```js
const myFirstQueue = new Bull('my-first-queue');

const job = await myFirstQueue.add({
  foo: 'bar'
});
```

As you can see a job is just a javascript object. This object needs to be serializable, more concrete it should be possible to JSON stringify it since that is how it is going to be stored in Redis.

It is also possible to provide an options object after the job's data, but we will cover that later on.

## Consumers

A consumer or worker (we will use these two terms interchangeably in this guide), is nothing more than a Node program
that defines a process function like so:

```js
const myFirstQueue = new Bull('my-first-queue');

myFirstQueue.process(async (job) => {
  return doSomething(job.data);
});
```

The `process` function will be called every time the worker is idling and there are jobs to process in the queue. Since
the consumer does not need to be online when the jobs are added, the queue could have many jobs already waiting in it. So then the process will be kept busy processing jobs one by one until all of them are done.

In the example above we define the process function as `async`, which is the highly recommended way to define them.
If your Node runtime does not support async/await, then you can just return a promise at the end of the process
function for a similar result.

The value returned by your process function will be stored in the jobs object and can be accessed later on, for example
in a listener for the `completed` event.

Sometimes you need to provide a job's _progress_ information to an external listener, this can be easily accomplished
by using the `progress` method on the job object:

```js
myFirstQueue.process(async (job) => {
  let progress = 0;
  for (i = 0; i < 100; i++) {
    await doSomething(job.data);
    progress += 10;
    job.progress(progress);
  }
});
```

## Listeners

Finally, you can just listen to events that happen in the queue. Listeners can be local, meaning that they only will
receive notifications produced in the _given queue instance_, or global, meaning that they listen to _all_ the events
for a given queue. So you can attach a listener to any instance, even instances that are acting as consumers or producers. But note that a local event will never fire if the queue is not a consumer or producer, you will need to use global events in that
case.

```js
const myFirstQueue = new Bull('my-first-queue');

// Define a local completed event
myFirstQueue.on('completed', (job, result) => {
  console.log(`Job completed with result ${result}`);
})
```

## A Job's Lifecycle

In order to use the full potential of Bull queues, it is important to understand the lifecycle of a job.
From the moment a producer calls the `add` method on a queue instance, a job enters a lifecycle where it will
be in different states, until its completion or failure (although technically a failed job could be retried and get a new lifecycle).

![Diagram showing job statuses](job-lifecycle.png)

When a job is added to a queue it can be in one of two states, it can either be in the "wait" status, which is, in fact, a waiting list, where all jobs must enter before they can be processed, or it can be in a "delayed" status: a delayed status implies that the job is waiting for some timeout or to be promoted for being processed. However, a delayed job will not be processed directly, instead, it will be placed at the beginning of the waiting list and processed as soon as a worker is idle.

The next state for a job is the "active" state. The active state is represented by a set, and are jobs that are currently being
processed, i.e. they are running in the `process` function explained in the previous chapter. A job can be in the active state for an unlimited amount of time until the process is completed or an exception is thrown so that the job will end in
either the "completed" or the "failed" status.

## Stalled jobs

In Bull, we defined the concept of stalled jobs. A stalled job is a job that is being processed but where Bull suspects that
the process function has hanged. This happens when the process function is processing a job and is keeping the CPU so busy that
the worker is not able to tell the queue that it is still working on the job.

When a job stalls, depending on the job settings the job can be retried by another idle worker or it can just move to the failed status.

Stalled jobs can be avoided by either making sure that the process function does not keep the Node event loop busy for too long (we are talking several seconds with Bull default options), or by using a separate [sandboxed processor](#sandboxed-processors).

# Events

A Queue in Bull generates a handful of events that are useful in many use cases.
Events can be local for a given queue instance (a worker), for example, if a job is completed in a given worker, a local event will be emitted just for that instance. However, it is possible to listen to all events, by prefixing ```global:``` to the local event name. Then we can listen to all the events produced by all the workers of a given queue.

A local complete event:

```js
queue.on('completed', job => {
  console.log(`Job with id ${job.id} has been completed`);
})
```

Whereas the global version of the event can be listened to with:

```js
queue.on('global:completed', jobId => {
  console.log(`Job with id ${jobId} has been completed`);
})
```

Note that signatures of global events are slightly different than their local counterpart, in the example above it is only sent the job id not a complete instance of the job itself, this is done for performance reasons.

The list of available events can be found in the [reference](https://github.com/OptimalBits/bull/blob/master/REFERENCE.md#eventsk).

# Queue Options

A queue can be instantiated with some useful options, for instance, you can specify the location and password of your Redis server,
as well as some other useful settings. All these settings are described in Bull's [reference](https://github.com/OptimalBits/bull/blob/master/REFERENCE.md#queue) and we will not repeat them here. However, we will go through some use cases.

## Rate Limiter

It is possible to create queues that limit the number of jobs processed in a unit of time. The limiter is defined per queue, independently of the number of workers, so you can scale horizontally and still limit the rate of processing easily:

```js
// Limit queue to max 1000 jobs per 5000 milliseconds.
const myRateLimitedQueue = new Queue('rateLimited', {
  limiter: {
    max: 1000,
    duration: 5000
  }
});
```

When a queue hits the rate limit, requested jobs will join the `delayed` queue.

## Named jobs

It is possible to give names to jobs. This does not change any of the mechanics of the queue but can be used for clearer code and
better visualization in UI tools:

```js
// Jobs producer
const myJob = await transcoderQueue.add('image', { input: 'myimagefile' });
const myJob = await transcoderQueue.add('audio', { input: 'myaudiofile' });
const myJob = await transcoderQueue.add('video', { input: 'myvideofile' });
```

```js
// Worker
transcoderQueue.process('image', processImage);
transcoderQueue.process('audio', processAudio);
transcoderQueue.process('video', processVideo);
```

Just keep in mind that every queue instance is required to provide a processor for *every* named job or you will get an exception.

## Sandboxed Processors

As explained above, when defining a process function, it is also possible to provide a concurrency setting. This setting allows the worker to process several
jobs in parallel. The jobs are still processed in the same Node process,
and if the jobs are very IO intensive they will be handled just fine.

Sometimes jobs are more CPU intensive which could lock the Node event loop
for too long and Bull could decide the job has been stalled. To avoid this situation, it is possible to run the process functions in separate Node processes. In this case, the concurrency parameter will decide the maximum number of concurrent processes that are allowed to run.

We call these kinds of processes "sandboxed" processes, and they also have the property that if they crash they will not affect any other process, and a new
process will be spawned automatically to replace it.


# Job types

The default job type in Bull is "FIFO" (first in first out), meaning that the jobs are processed in the same order they are coming into the
queue. Sometimes it is useful to process jobs in a different order.

## LIFO

Lifo (last in first out) means that jobs are added to the beginning of the queue and therefore will be processed as soon as the worker is idle.

```js
const myJob = await myqueue.add({ foo: 'bar' }, { lifo: true });
```

## Delayed

It is also possible to add jobs to the queue that are delayed a certain amount of time before they will be processed. Note that the delay parameter means the _minimum_ amount of time the job will wait before being processed. When the delay time has passed the job will be moved to the beginning of the queue and be processed as soon as a worker is idle.

```js
// Delayed 5 seconds
const myJob = await myqueue.add({ foo: 'bar' }, { delay: 5000 });
```

## Prioritized

Jobs can be added to a queue with a priority value. Jobs with higher priority will be processed before jobs with lower priority. The highest priority is 1, and the larger the integer you use, the lower the priority of the job. Keep in mind that priority queues are a bit slower than a standard queue (currently insertion time O(n), n being the number of jobs currently waiting in the queue, instead of O(1) for standard queues).

```js
const myJob = await myqueue.add({ foo: 'bar' }, { priority: 3 });
```

## Repeatable

Repeatable jobs are special jobs that repeat themselves indefinitely or until a given maximum date or the number of repetitions has been reached, according to a cron specification or a time interval.

```js
// Repeat every 10 seconds for 100 times.
const myJob = await myqueue.add(
  { foo: 'bar' },
  {
    repeat: {
      every: 10000,
      limit: 100
    }
  }
);

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

There are some important considerations regarding repeatable jobs:

- Bull is smart enough not to add the same repeatable job if the repeat options are the same. (CAUTION: A job id is part of the repeat options since: https://github.com/OptimalBits/bull/pull/603, therefore passing job ids will allow jobs with the same cron to be inserted in the queue)
- If there are no workers running, repeatable jobs will not accumulate the next time a worker is online.
- Repeatable jobs can be removed using the [removeRepeatable](https://github.com/OptimalBits/bull/blob/master/REFERENCE.md#queueremoverepeatable) method.


================================================
FILE: docs/_config.yml
================================================
theme: jekyll-theme-minimal
title: Welcome to Bull's Guide


================================================
FILE: generateRawScripts.js
================================================
'use strict';
const { ScriptLoader } = require('./lib/commands');
const path = require('path');
const fs = require('fs');
const { promisify } = require('util');

const writeFile = promisify(fs.writeFile);

class RawScriptLoader extends ScriptLoader {
  /**
   * Transpile lua scripts in one file, specifying an specific directory to be saved
   * @param pathname - the path to the directory containing the scripts
   * @param writeDir - the path to the directory where scripts will be saved
   */
  async transpileScripts(pathname, writeDir) {
    const writeFilenamePath = path.normalize(writeDir);

    if (!fs.existsSync(writeFilenamePath)) {
      fs.mkdirSync(writeFilenamePath);
    }

    const paths = new Set();
    if (!paths.has(pathname)) {
      paths.add(pathname);
      const scripts = await this.loadScripts(pathname);
      for (const command of scripts) {
        const {
          name,
          options: { numberOfKeys, lua }
        } = command;
        await writeFile(
          path.join(writeFilenamePath, `${name}-${numberOfKeys}.lua`),
          lua
        );
      }
    }
  }
}

const scriptLoader = new RawScriptLoader();

scriptLoader.transpileScripts(
  path.join(__dirname, './lib/commands'),
  path.join(__dirname, './rawScripts')
);


================================================
FILE: index.d.ts
================================================
// Type definitions for bull 3.15
// Project: https://github.com/OptimalBits/bull
// Definitions by: Bruno Grieder <https://github.com/bgrieder>
//                 Cameron Crothers <https://github.com/JProgrammer>
//                 Marshall Cottrell <https://github.com/marshall007>
//                 Weeco <https://github.com/weeco>
//                 Oleg Repin <https://github.com/iamolegga>
//                 David Koblas <https://github.com/koblas>
//                 Bond Akinmade <https://github.com/bondz>
//                 Wuha Team <https://github.com/wuha-team>
//                 Alec Brunelle <https://github.com/aleccool213>
//                 Dan Manastireanu <https://github.com/danmana>
//                 Kjell-Morten Bratsberg Thorsen <https://github.com/kjellmorten>
//                 Christian D. <https://github.com/pc-jedi>
//                 Silas Rech <https://github.com/lenovouser>
//                 DoYoung Ha <https://github.com/hados99>
//                 Borys Kupar <https://github.com/borys-kupar>
//                 Remko Klein <https://github.com/remko79>
//                 Levi Bostian <https://github.com/levibostian>
//                 Todd Dukart <https://github.com/tdukart>
//                 Mix <https://github.com/mnixry>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8

import * as Redis from 'ioredis';
import { EventEmitter } from 'events';

/**
 * This is the Queue constructor.
 * It creates a new Queue that is persisted in Redis.
 * Everytime the same queue is instantiated it tries to process all the old jobs that may exist from a previous unfinished session.
 */
declare const Bull: {
  /* tslint:disable:no-unnecessary-generics unified-signatures */
  <T = any>(queueName: string, opts?: Bull.QueueOptions): Bull.Queue<T>;
  <T = any>(
    queueName: string,
    url: string,
    opts?: Bull.QueueOptions
  ): Bull.Queue<T>;
  new <T = any>(queueName: string, opts?: Bull.QueueOptions): Bull.Queue<T>;
  new <T = any>(
    queueName: string,
    url: string,
    opts?: Bull.QueueOptions
  ): Bull.Queue<T>;
  /* tslint:enable:no-unnecessary-generics unified-signatures */
};

declare namespace Bull {
  interface RateLimiter {
    /** Max numbers of jobs processed */
    max: number;
    /** Per duration in milliseconds */
    duration: number;
    /** When jobs get rate limited, they stay in the waiting queue and are not moved to the delayed queue */
    bounceBack?: boolean | undefined;
    /** Groups jobs with the specified key from the data object passed to the Queue#add ex. "network.handle" */
    groupKey?: string | undefined;
  }

  interface QueueOptions {
    /**
     * Options passed into the `ioredis` constructor's `options` parameter.
     * `connectionName` is overwritten with `Queue.clientName()`. other properties are copied
     */
    redis?: Redis.RedisOptions | string | undefined;

    /**
     * When specified, the `Queue` will use this function to create new `ioredis` client connections.
     * This is useful if you want to re-use connections or connect to a Redis cluster.
     */
    createClient?(
      type: 'client' | 'subscriber' | 'bclient',
      redisOpts?: Redis.RedisOptions
    ): Redis.Redis | Redis.Cluster;

    /**
     * Prefix to use for all redis keys
     */
    prefix?: string | undefined;

    settings?: AdvancedSettings | undefined;

    limiter?: RateLimiter | undefined;

    defaultJobOptions?: JobOptions | undefined;

    metrics?: MetricsOpts; // Configure metrics
  }

  interface MetricsOpts {
    maxDataPoints?: number; //  Max number of data points to collect, granularity is fixed at one minute.
  }

  interface AdvancedSettings {
    /**
     * Key expiration time for job locks
     */
    lockDuration?: number | undefined;

    /**
     * Interval in milliseconds on which to acquire the job lock.
     */
    lockRenewTime?: number | undefined;

    /**
     * How often check for stalled jobs (use 0 for never checking)
     */
    stalledInterval?: number | undefined;

    /**
     * Max amount of times a stalled job will be re-processed
     */
    maxStalledCount?: number | undefined;

    /**
     * Poll interval for delayed jobs and added jobs
     */
    guardInterval?: number | undefined;

    /**
     * Delay before processing next job in case of internal error
     */
    retryProcessDelay?: number | undefined;

    /**
     * Define a custom backoff strategy
     */
    backoffStrategies?:
      | {
          [key: string]: (
            attemptsMade: number,
            err: Error,
            strategyOptions?: any
          ) => number;
        }
      | undefined;

    /**
     * A timeout for when the queue is in `drained` state (empty waiting for jobs).
     * It is used when calling `queue.getNextJob()`, which will pass it to `.brpoplpush` on the Redis client.
     */
    drainDelay?: number | undefined;
  }

  type DoneCallback = (error?: Error | null, value?: any) => void;

  type JobId = number | string;

  type ProcessCallbackFunction<T> = (job: Job<T>, done: DoneCallback) => void;
  type ProcessPromiseFunction<T> = (job: Job<T>) => Promise<void>;

  interface Job<T = any> {
    id: JobId;

    /**
     * The custom data passed when the job was created
     */
    data: T;

    /**
     * Options of the job
     */
    opts: JobOptions;

    /**
     * How many attempts where made to run this job
     */
    attemptsMade: number;

    /**
     * When this job was started (unix milliseconds)
     */
    processedOn?: number | undefined;

    /**
     * When this job was completed (unix milliseconds)
     */
    finishedOn?: number | undefined;

    /**
     * Which queue this job was part of
     */
    queue: Queue<T>;

    timestamp: number;

    /**
     * The named processor name
     */
    name: string;

    /**
     * The stacktrace for any errors
     */
    stacktrace: string[];

    returnvalue: any;

    failedReason?: string | undefined;

    /**
     * Get progress on a job
     */
    progress(): any;

    /**
     * Report progress on a job
     */
    progress(value: any): Promise<void>;

    /**
     * Logs one row of log data.
     *
     * @param row String with log data to be logged.
     */
    log(row: string): Promise<any>;

    /**
     * Returns a promise resolving to a boolean which, if true, current job's state is completed
     */
    isCompleted(): Promise<boolean>;

    /**
     * Returns a promise resolving to a boolean which, if true, current job's state is failed
     */
    isFailed(): Promise<boolean>;

    /**
     * Returns a promise resolving to a boolean which, if true, current job's state is delayed
     */
    isDelayed(): Promise<boolean>;

    /**
     * Returns a promise resolving to a boolean which, if true, current job's state is active
     */
    isActive(): Promise<boolean>;

    /**
     * Returns a promise resolving to a boolean which, if true, current job's state is wait
     */
    isWaiting(): Promise<boolean>;

    /**
     * Returns a promise resolving to a boolean which, if true, current job's state is paused
     */
    isPaused(): Promise<boolean>;

    /**
     * Returns a promise resolving to a boolean which, if true, current job's state is stuck
     */
    isStuck(): Promise<boolean>;

    /**
     * Returns a promise resolving to the current job's status.
     * Please take note that the implementation of this method is not very efficient, nor is
     * it atomic. If your queue does have a very large quantity of jobs, you may want to
     * avoid using this method.
     */
    getState(): Promise<JobStatus | 'stuck'>;

    /**
     * Update a specific job's data. Promise resolves when the job has been updated.
     */
    update(data: T): Promise<void>;

    /**
     * Removes a job from the queue and from any lists it may be included in.
     * The returned promise resolves when the job has been removed.
     */
    remove(): Promise<void>;

    /**
     * Re-run a job that has failed. The returned promise resolves when the job
     * has been scheduled for retry.
     */
    retry(): Promise<void>;

    /**
     * Ensure this job is never ran again even if attemptsMade is less than job.attempts.
     */
    discard(): Promise<void>;

    /**
     * Returns a promise that resolves to the returned data when the job has been finished.
     */
    finished(): Promise<any>;

    /**
     * Moves a job to the `completed` queue. Pulls a job from 'waiting' to 'active'
     * and returns a tuple containing the next jobs data and id. If no job is in the `waiting` queue, returns null.
     */
    moveToCompleted(
      returnValue?: string,
      ignoreLock?: boolean,
      notFetch?: boolean
    ): Promise<[any, JobId] | null>;

    /**
     * Moves a job to the `failed` queue. Pulls a job from 'waiting' to 'active'
     * and returns a tuple containing the next jobs data and id. If no job is in the `waiting` queue, returns null.
     */
    moveToFailed(
      errorInfo: { message: string },
      ignoreLock?: boolean
    ): Promise<[any, JobId] | null>;

    /**
     * Promotes a job that is currently "delayed" to the "waiting" state and executed as soon as possible.
     */
    promote(): Promise<void>;

    /**
     * Return a unique key representing a lock for this Job
     */
    lockKey(): string;

    /**
     * Releases the lock on the job. Only locks owned by the queue instance can be released.
     */
    releaseLock(): Promise<void>;

    /**
     * Takes a lock for this job so that no other queue worker can process it at the same time.
     */
    takeLock(): Promise<number | false>;

    /**
     * Extend the lock for this job.
     *
     * @param duration lock duration in milliseconds
     */
    extendLock(duration: number): Promise<number>

    /**
     * Get job properties as Json Object
     */
    toJSON(): {
      id: JobId;
      name: string;
      data: T;
      opts: JobOptions;
      progress: number;
      delay: number;
      timestamp: number;
      attemptsMade: number;
      failedReason: any;
      stacktrace: string[] | null;
      returnvalue: any;
      finishedOn: number | null;
      processedOn: number | null;
    };
  }

  type JobStatus =
    | 'completed'
    | 'waiting'
    | 'active'
    | 'delayed'
    | 'failed'
    | 'paused';
  type JobStatusClean =
    | 'completed'
    | 'wait'
    | 'active'
    | 'delayed'
    | 'failed'
    | 'paused';

  interface BackoffOptions {
    /**
     * Backoff type, which can be either `fixed` or `exponential`
     */
    type: string;

    /**
     * Backoff delay, in milliseconds
     */
    delay?: number | undefined;

    /**
     * Options for custom strategies
     */
    options?: any;
  }

  interface RepeatOptions {
    /**
     * Timezone
     */
    tz?: string | undefined;

    /**
     * End date when the repeat job should stop repeating
     */
    endDate?: Date | string | number | undefined;

    /**
     * Number of times the job should repeat at max.
     */
    limit?: number | undefined;

    /**
     * The start value for the repeat iteration count.
     */
    count?: number | undefined;
  }

  interface CronRepeatOptions extends RepeatOptions {
    /**
     * Cron pattern specifying when the job should execute
     */
    cron: string;

    /**
     * Start date when the repeat job should start repeating (only with cron).
     */
    startDate?: Date | string | number | undefined;
  }

  interface EveryRepeatOptions extends RepeatOptions {
    /**
     * Repeat every millis (cron setting cannot be used together with this setting.)
     */
    every: number;
  }

  interface DebounceOptions {
    /**
     * ttl in milliseconds
     */
    ttl?: number;
    /**
     * Identifier
     */
    id: string;
  }

  interface JobOptions {
    /**
     * Debounce options.
     */
    debounce?: DebounceOptions;

    /**
     * Optional priority value. ranges from 1 (highest priority) to MAX_INT  (lowest priority).
     * Note that using priorities has a slight impact on performance, so do not use it if not required
     */
    priority?: number | undefined;

    /**
     * An amount of miliseconds to wait until this job can be processed.
     * Note that for accurate delays, both server and clients should have their clocks synchronized. [optional]
     */
    delay?: number | undefined;

    /**
     * The total number of attempts to try the job until it completes
     */
    attempts?: number | undefined;

    /**
     * Repeat job according to a cron specification
     */
    repeat?:
      | ((CronRepeatOptions | EveryRepeatOptions) & {
          /**
           * The key for the repeatable job metadata in Redis.
           */
          readonly key?: string;
        })
      | undefined;

    /**
     * Backoff setting for automatic retries if the job fails
     */
    backoff?: number | BackoffOptions | undefined;

    /**
     * A boolean which, if true, adds the job to the right
     * of the queue instead of the left (default false)
     */
    lifo?: boolean | undefined;

    /**
     *  The number of milliseconds after which the job should be fail with a timeout error
     */
    timeout?: number | undefined;

    /**
     * Override the job ID - by default, the job ID is a unique
     * integer, but you can use this setting to override it.
     * If you use this option, it is up to you to ensure the
     * jobId is unique. If you attempt to add a job with an id that
     * already exists, it will not be added.
     */
    jobId?: JobId | undefined;

    /**
     * A boolean which, if true, removes the job when it successfully completes.
     * When a number, it specifies the amount of jobs to keep.
     * Default behavior is to keep the job in the completed set.
     * See KeepJobsOptions if using that interface instead.
     */
    removeOnComplete?: boolean | number | KeepJobsOptions | undefined;

    /**
     * A boolean which, if true, removes the job when it fails after all attempts.
     * When a number, it specifies the amount of jobs to keep.
     * Default behavior is to keep the job in the failed set.
     * See KeepJobsOptions if using that interface instead.
     */
    removeOnFail?: boolean | number | KeepJobsOptions | undefined;

    /**
     * Limits the amount of stack trace lines that will be recorded in the stacktrace.
     */
    stackTraceLimit?: number | undefined;

    /**
     * Prevents JSON data from being parsed.
     */
    preventParsingData?: boolean | undefined;
  }

  /**
   * Specify which jobs to keep after finishing processing this job.
   * If both age and count are specified, then the jobs kept will be the ones that satisfies both properties.
   */
  interface KeepJobsOptions {
    /**
     * Maximum age in *seconds* for job to be kept.
     */
    age?: number | undefined;

    /**
     * Maximum count of jobs to be kept.
     */
    count?: number | undefined;
  }

  interface JobCounts {
    active: number;
    completed: number;
    failed: number;
    delayed: number;
    waiting: number;
  }

  interface JobInformation {
    key: string;
    name: string;
    id?: string | undefined;
    endDate?: number | undefined;
    tz?: string | undefined;
    cron: string;
    every: number;
    next: number;
  }

  interface Queue<T = any> extends EventEmitter {
    /**
     * The name of the queue
     */
    name: string;

    /**
     * Queue client (used to add jobs, pause queues, etc);
     */
    client: Redis.Redis;

    /**
     * Returns a promise that resolves when Redis is connected and the queue is ready to accept jobs.
     * This replaces the `ready` event emitted on Queue in previous verisons.
     */
    isReady(): Promise<this>;

    /* tslint:disable:unified-signatures */

    /**
     * Defines a processing function for the jobs placed into a given Queue.
     *
     * The callback is called everytime a job is placed in the queue.
     * It is passed an instance of the job as first argument.
     *
     * If the callback signature contains the second optional done argument,
     * the callback will be passed a done callback to be called after the job has been completed.
     * The done callback can be called with an Error instance, to signal that the job did not complete successfully,
     * or with a result as second argument (e.g.: done(null, result);) when the job is successful.
     * Errors will be passed as a second argument to the "failed" event; results, as a second argument to the "completed" event.
     *
     * If, however, the callback signature does not contain the done argument,
     * a promise must be returned to signal job completion.
     * If the promise is rejected, the error will be passed as a second argument to the "failed" event.
     * If it is resolved, its value will be the "completed" event's second argument.
     */
    process(callback: ProcessCallbackFunction<T>): Promise<void>;
    process(callback: ProcessPromiseFunction<T>): Promise<void>;
    process(callback: string): Promise<void>;

    /**
     * Defines a processing function for the jobs placed into a given Queue.
     *
     * The callback is called everytime a job is placed in the queue.
     * It is passed an instance of the job as first argument.
     *
     * If the callback signature contains the second optional done argument,
     * the callback will be passed a done callback to be called after the job has been completed.
     * The done callback can be called with an Error instance, to signal that the job did not complete successfully,
     * or with a result as second argument (e.g.: done(null, result);) when the job is successful.
     * Errors will be passed as a second argument to the "failed" event; results, as a second argument to the "completed" event.
     *
     * If, however, the callback signature does not contain the done argument,
     * a promise must be returned to signal job completion.
     * If the promise is rejected, the error will be passed as a second argument to the "failed" event.
     * If it is resolved, its value will be the "completed" event's second argument.
     *
     * @param concurrency Bull will then call your handler in parallel respecting this maximum value.
     */
    process(
      concurrency: number,
      callback: ProcessCallbackFunction<T>
    ): Promise<void>;
    process(
      concurrency: number,
      callback: ProcessPromiseFunction<T>
    ): Promise<void>;
    process(concurrency: number, callback: string): Promise<void>;

    /**
     * Defines a processing function for the jobs placed into a given Queue.
     *
     * The callback is called everytime a job is placed in the queue.
     * It is passed an instance of the job as first argument.
     *
     * If the callback signature contains the second optional done argument,
     * the callback will be passed a done callback to be called after the job has been completed.
     * The done callback can be called with an Error instance, to signal that the job did not complete successfully,
     * or with a result as second argument (e.g.: done(null, result);) when the job is successful.
     * Errors will be passed as a second argument to the "failed" event; results, as a second argument to the "completed" event.
     *
     * If, however, the callback signature does not contain the done argument,
     * a promise must be returned to signal job completion.
     * If the promise is rejected, the error will be passed as a second argument to the "failed" event.
     * If it is resolved, its value will be the "completed" event's second argument.
     *
     * @param name Bull will only call the handler if the job name matches
     */
    process(name: string, callback: ProcessCallbackFunction<T>): Promise<void>;
    process(name: string, callback: ProcessPromiseFunction<T>): Promise<void>;
    process(name: string, callback: string): Promise<void>;

    /**
     * Defines a processing function for the jobs placed into a given Queue.
     *
     * The callback is called everytime a job is placed in the queue.
     * It is passed an instance of the job as first argument.
     *
     * If the callback signature contains the second optional done argument,
     * the callback will be passed a done callback to be called after the job has been completed.
     * The done callback can be called with an Error instance, to signal that the job did not complete successfully,
     * or with a result as second argument (e.g.: done(null, result);) when the job is successful.
     * Errors will be passed as a second argument to the "failed" event; results, as a second argument to the "completed" event.
     *
     * If, however, the callback signature does not contain the done argument,
     * a promise must be returned to signal job completion.
     * If the promise is rejected, the error will be passed as a second argument to the "failed" event.
     * If it is resolved, its value will be the "completed" event's second argument.
     *
     * @param name Bull will only call the handler if the job name matches
     * @param concurrency Bull will then call your handler in parallel respecting this maximum value.
     */
    process(
      name: string,
      concurrency: number,
      callback: ProcessCallbackFunction<T>
    ): Promise<void>;
    process(
      name: string,
      concurrency: number,
      callback: ProcessPromiseFunction<T>
    ): Promise<void>;
    process(name: string, concurrency: number, callback: string): Promise<void>;

    /* tslint:enable:unified-signatures */

    /**
     * Creates a new job and adds it to the queue.
     * If the queue is empty the job will be executed directly,
     * otherwise it will be placed in the queue and executed as soon as possible.
     */
    add(data: T, opts?: JobOptions): Promise<Job<T>>;

    /**
     * Creates a new named job and adds it to the queue.
     * If the queue is empty the job will be executed directly,
     * otherwise it will be placed in the queue and executed as soon as possible.
     */
    add(name: string, data: T, opts?: JobOptions): Promise<Job<T>>;

    /**
     * Adds an array of jobs to the queue.
     * If the queue is empty the jobs will be executed directly,
     * otherwise they will be placed in the queue and executed as soon as possible.
     * 'repeat' option is not supported in addBulk https://github.com/OptimalBits/bull/issues/1731
     */
    addBulk(
      jobs: Array<{
        name?: string | undefined;
        data: T;
        opts?: Omit<JobOptions, 'repeat'> | undefined;
      }>
    ): Promise<Array<Job<T>>>;

    /**
     * Returns a promise that resolves when the queue is paused.
     *
     * A paused queue will not process new jobs until resumed, but current jobs being processed will continue until
     * they are finalized. The pause can be either global or local. If global, all workers in all queue instances
     * for a given queue will be paused. If local, just this worker will stop processing new jobs after the current
     * lock expires. This can be useful to stop a worker from taking new jobs prior to shutting down.
     *
     * If doNotWaitActive is true, pause will not wait for any active jobs to finish before resolving. Otherwise, pause
     * will wait for active jobs to finish. See Queue#whenCurrentJobsFinished for more information.
     *
     * Pausing a queue that is already paused does nothing.
     */
    pause(isLocal?: boolean, doNotWaitActive?: boolean): Promise<void>;

    /**
     * Returns a promise that resolves when the queue is resumed after being paused.
     *
     * The resume can be either local or global. If global, all workers in all queue instances for a given queue
     * will be resumed. If local, only this worker will be resumed. Note that resuming a queue globally will not
     * resume workers that have been paused locally; for those, resume(true) must be called directly on their
     * instances.
     *
     * Resuming a queue that is not paused does nothing.
     */
    resume(isLocal?: boolean): Promise<void>;

    /**
     * Returns a promise that resolves with a boolean if queue is paused
     */
    isPaused(isLocal?: boolean): Promise<boolean>;

    /**
     * Returns a promise that returns the number of jobs in the queue, waiting or paused.
     * Since there may be other processes adding or processing jobs, this value may be true only for a very small amount of time.
     */
    count(): Promise<number>;

    /**
     * Empties a queue deleting all the input lists and associated jobs.
     */
    empty(): Promise<void>;

    /**
     * Closes the underlying redis client. Use this to perform a graceful shutdown.
     *
     * `close` can be called from anywhere, with one caveat:
     * if called from within a job handler the queue won't close until after the job has been processed
     */
    close(doNotWaitJobs?: boolean): Promise<void>;

    /**
     * Returns the number of jobs per priority.
     */
    getCountsPerPriority(priorities: number[]): Promise<{
      [index: string]: number;
    }>;

    /**
     * Returns a promise that will return the job instance associated with the jobId parameter.
     * If the specified job cannot be located, the promise callback parameter will be set to null.
     */
    getJob(jobId: JobId): Promise<Job<T> | null>;

    /**
     * Returns a promise that will return an array with the waiting jobs between start and end.
     */
    getWaiting(start?: number, end?: number): Promise<Array<Job<T>>>;

    /**
     * Returns a promise that will return an array with the active jobs between start and end.
     */
    getActive(start?: number, end?: number): Promise<Array<Job<T>>>;

    /**
     * Returns a promise that will return an array with the delayed jobs between start and end.
     */
    getDelayed(start?: number, end?: number): Promise<Array<Job<T>>>;

    /**
     * Returns a promise that will return an array with the completed jobs between start and end.
     */
    getCompleted(start?: number, end?: number): Promise<Array<Job<T>>>;

    /**
     * Returns a promise that will return an array with the failed jobs between start and end.
     */
    getFailed(start?: number, end?: number): Promise<Array<Job<T>>>;

    /**
     * Returns JobInformation of repeatable jobs (ordered descending). Provide a start and/or an end
     * index to limit the number of results. Start defaults to 0, end to -1 and asc to false.
     */
    getRepeatableJobs(
      start?: number,
      end?: number,
      asc?: boolean
    ): Promise<JobInformation[]>;

    /**
     * ???
     */
    nextRepeatableJob(
      name: string,
      data: any,
      opts: JobOptions
    ): Promise<Job<T>>;

    /**
     * Removes a given repeatable job. The RepeatOptions and JobId needs to be the same as the ones
     * used for the job when it was added.
     */
    removeRepeatable(
      repeat: (CronRepeatOptions | EveryRepeatOptions) & {
        jobId?: JobId | undefined;
      }
    ): Promise<void>;

    /**
     * Removes a given repeatable job. The RepeatOptions and JobId needs to be the same as the ones
     * used for the job when it was added.
     *
     * name: The name of the to be removed job
     */
    removeRepeatable(
      name: string,
      repeat: (CronRepeatOptions | EveryRepeatOptions) & {
        jobId?: JobId | undefined;
      }
    ): Promise<void>;

    /**
     * Removes a given repeatable job by key.
     */
    removeRepeatableByKey(key: string): Promise<void>;

    /**
     * Returns a promise that will return an array of job instances of the given job statuses.
     * Optional parameters for range and ordering are provided.
     */
    getJobs(
      types: JobStatus[],
      start?: number,
      end?: number,
      asc?: boolean
    ): Promise<Array<Job<T>>>;

    /**
     * Returns a promise that resolves to a Metrics object.
     */
    getMetrics(type: 'completed' | 'failed', start?: number, end?: number): Promise<{
      meta: {
        count: number;
        prevTS: number;
        prevCount: number;
      };
      data: number[];
      count: number;
    }>

    /**
     * Returns a promise that resolves to the next job in queue.
     */
    getNextJob(): Promise<Job<T> | undefined>;

    /**
     * Returns a object with the logs according to the start and end arguments. The returned count
     * value is the total amount of logs, useful for implementing pagination.
     */
    getJobLogs(
      jobId: JobId,
      start?: number,
      end?: number
    ): Promise<{ logs: string[]; count: number }>;

    /**
     * Returns a promise that resolves with the job counts for the given queue.
     */
    getJobCounts(): Promise<JobCounts>;

    /**
     * Returns a promise that resolves with the job counts for the given queue of the given job statuses.
     */
    getJobCountByTypes(types: JobStatus[] | JobStatus): Promise<number>;

    /**
     * Returns a promise that resolves with the quantity of completed jobs.
     */
    getCompletedCount(): Promise<number>;

    /**
     * Returns a promise that resolves with the quantity of failed jobs.
     */
    getFailedCount(): Promise<number>;

    /**
     * Returns a promise that resolves with the quantity of delayed jobs.
     */
    getDelayedCount(): Promise<number>;

    /**
     * Returns a promise that resolves with the quantity of waiting jobs.
     */
    getWaitingCount(): Promise<number>;

    /**
     * Returns a promise that resolves with the quantity of paused jobs.
     */
    getPausedCount(): Promise<number>;

    /**
     * Returns a promise that resolves with the quantity of active jobs.
     */
    getActiveCount(): Promise<number>;

    /**
     * Returns a promise that resolves to the quantity of repeatable jobs.
     */
    getRepeatableCount(): Promise<number>;

    /**
     * Tells the queue remove all jobs created outside of a grace period in milliseconds.
     * You can clean the jobs with the following states: completed, wait (typo for waiting), active, delayed, and failed.
     * @param grace Grace period in milliseconds.
     * @param status Status of the job to clean. Values are completed, wait, active, delayed, and failed. Defaults to completed.
     * @param limit Maximum amount of jobs to clean per call. If not provided will clean all matching jobs.
     */
    clean(
      grace: number,
      status?: JobStatusClean,
      limit?: number
    ): Promise<Array<Job<T>>>;

    /**
     * Returns a promise that resolves to a Metrics object.
     * @param type Job metric type either 'completed' or 'failed'
     * @param start Start point of the metrics, where 0 is the newest point to be returned.
     * @param end End point of the metrics, where -1 is the oldest point to be returned.
     * @returns - Returns an object with queue metrics.
     */
    getMetrics(
      type: 'completed' | 'failed',
      start?: number,
      end?: number
    ): Promise<{
      meta: {
        count: number;
        prevTS: number;
        prevCount: number;
      };
      data: number[];
      count: number;
    }>;

    /**
     * Returns a promise that marks the start of a transaction block.
     */
    multi(): Redis.Pipeline;

    /**
     * Returns the queue specific key.
     */
    toKey(queueType: string): string;

    /**
     * Completely destroys the queue and all of its contents irreversibly.
     * @param ops.force Obliterate the queue even if there are active jobs
     */
    obliterate(ops?: { force: boolean }): Promise<void>;

    /**
     * Listens to queue events
     */
    on(event: string, callback: (...args: any[]) => void): this;

    /**
     * An error occured
     */
    on(event: 'error', callback: ErrorEventCallback): this;

    /**
     * A Job is waiting to be processed as soon as a worker is idling.
     */
    on(event: 'waiting', callback: WaitingEventCallback): this;

    /**
     * A job has started. You can use `jobPromise.cancel()` to abort it
     */
    on(event: 'active', callback: ActiveEventCallback<T>): this;

    /**
     * A job has been marked as stalled.
     * This is useful for debugging job workers that crash or pause the event loop.
     */
    on(event: 'stalled', callback: StalledEventCallback<T>): this;

    /**
     * A job's progress was updated
     */
    on(event: 'progress', callback: ProgressEventCallback<T>): this;

    /**
     * A job successfully completed with a `result`
     */
    on(event: 'completed', callback: CompletedEventCallback<T>): this;

    /**
     * A job failed with `err` as the reason
     */
    on(event: 'failed', callback: FailedEventCallback<T>): this;

    /**
     * The queue has been paused
     */
    on(event: 'paused', callback: EventCallback): this;

    /**
     * The queue has been resumed
     */
    on(event: 'resumed', callback: EventCallback): this; // tslint:disable-line unified-signatures

    /**
     * A job successfully removed.
     */
    on(event: 'removed', callback: RemovedEventCallback<T>): this;

    /**
     * Old jobs have been cleaned from the queue.
     * `jobs` is an array of jobs that were removed, and `type` is the type of those jobs.
     *
     * @see Queue#clean() for details
     */
    on(event: 'cleaned', callback: CleanedEventCallback<T>): this;

    /**
     * Emitted every time the queue has processed all the waiting jobs
     * (even if there can be some delayed jobs not yet processed)
     */
    on(event: 'drained', callback: EventCallback): this; // tslint:disable-line unified-signatures

    /**
     * Array of Redis clients the queue uses
     */
    clients: Redis.Redis[];

    /**
     * Set clientName to Redis.client
     */
    setWorkerName(): Promise<any>;

    /**
     * Returns array of workers that are currently working on this queue.
     */
    getWorkers(): Promise<{ [index: string]: string }[]>;

    /**
     * Returns Queue name in base64 encoded format
     */
    base64Name(): string;

    /**
     * Returns Queue name with keyPrefix (default: 'bull')
     */
    clientName(): string;

    /**
     * Returns Redis clients array which belongs to current Queue from string with all redis clients
     *
     * @param list String with all redis clients
     */
    parseClientList(list: string): { [index: string]: string }[][];

    /**
     * Returns a promise that resolves when active jobs are finished
     */
    whenCurrentJobsFinished(): Promise<void>;

    /**
     * Removes all the jobs which jobId matches the given pattern. The pattern must follow redis glob-style pattern
     * (syntax)[redis.io/commands/keys]
     */
    removeJobs(pattern: string): Promise<void>;
  }

  type EventCallback = () => void;

  type ErrorEventCallback = (error: Error) => void;

  interface JobPromise {
    /**
     * Abort this job
     */
    cancel(): void;
  }

  type ActiveEventCallback<T = any> = (
    job: Job<T>,
    jobPromise?: JobPromise
  ) => void;

  type StalledEventCallback<T = any> = (job: Job<T>) => void;

  type ProgressEventCallback<T = any> = (job: Job<T>, progress: any) => void;

  type CompletedEventCallback<T = any> = (job: Job<T>, result: any) => void;

  type FailedEventCallback<T = any> = (job: Job<T>, error: Error) => void;

  type CleanedEventCallback<T = any> = (
    jobs: Array<Job<T>>,
    status: JobStatusClean
  ) => void;

  type RemovedEventCallback<T = any> = (job: Job<T>) => void;

  type WaitingEventCallback = (jobId: JobId) => void;
}

export = Bull;


================================================
FILE: index.js
================================================
'use strict';

module.exports = require('./lib/queue');
module.exports.Job = require('./lib/job');
module.exports.utils = require('./lib/utils');


================================================
FILE: lib/backoffs.js
================================================
'use strict';

const _ = require('lodash');

const builtinStrategies = {
  fixed(delay) {
    return function() {
      return delay;
    };
  },

  exponential(delay) {
    return function(attemptsMade) {
      return Math.round((Math.pow(2, attemptsMade) - 1) * delay);
    };
  }
};

function lookupStrategy(backoff, customStrategies) {
  if (backoff.type in customStrategies) {
    return customStrategies[backoff.type];
  } else if (backoff.type in builtinStrategies) {
    return builtinStrategies[backoff.type](backoff.delay);
  } else {
    throw new Error(
      'Unknown backoff strategy ' +
        backoff.type +
        '. If a custom backoff strategy is used, specify it when the queue is created.'
    );
  }
}

module.exports = {
  normalize(backoff) {
    if (_.isFinite(backoff)) {
      return {
        type: 'fixed',
        delay: backoff
      };
    } else if (backoff) {
      return backoff;
    }
  },

  calculate(backoff, attemptsMade, customStrategies, err, strategyOptions) {
    if (backoff) {
      const strategy = lookupStrategy(
        backoff,
        customStrategies,
        strategyOptions
      );

      return strategy(attemptsMade, err, strategyOptions);
    }
  }
};


================================================
FILE: lib/commands/addJob-6.lua
================================================
--[[
  Adds a job to the queue by doing the following:
    - Increases the job counter if needed.
    - Creates a new job key with the job data.

    - if delayed:
      - computes timestamp.
      - adds to delayed zset.
      - Emits a global event 'delayed' if the job is delayed.
    - if not delayed
      - Adds the jobId to the wait/paused list in one of three ways:
         - LIFO
         - FIFO
         - prioritized.
      - Adds the job to the "added" list so that workers gets notified.

    Input:
      KEYS[1] 'wait',
      KEYS[2] 'paused'
      KEYS[3] 'meta-paused'
      KEYS[4] 'id'
      KEYS[5] 'delayed'
      KEYS[6] 'priority'

      ARGV[1]  key prefix,
      ARGV[2]  custom id (will not generate one automatically)
      ARGV[3]  name
      ARGV[4]  data (json stringified job data)
      ARGV[5]  opts (json stringified job opts)
      ARGV[6]  timestamp
      ARGV[7]  delay
      ARGV[8]  delayedTimestamp
      ARGV[9]  priority
      ARGV[10] LIFO
      ARGV[11] token
      ARGV[12] debounce key
      ARGV[13] debounceId
      ARGV[14] debounceTtl
]]
local jobId
local jobIdKey
local rcall = redis.call

-- Includes
--- @include "includes/addJobWithPriority"
--- @include "includes/debounceJob"
--- @include "includes/getTargetQueueList"

local jobCounter = rcall("INCR", KEYS[4])

if ARGV[2] == "" then
  jobId = jobCounter
  jobIdKey = ARGV[1] .. jobId
else
  jobId = ARGV[2]
  jobIdKey = ARGV[1] .. jobId
  if rcall("EXISTS", jobIdKey) == 1 then
    rcall("PUBLISH", ARGV[1] .. "duplicated@" .. ARGV[11], jobId)
    return jobId .. "" -- convert to string
  end
end

local debounceKey = ARGV[12]

local opts = cmsgpack.unpack(ARGV[5])

local debouncedJobId = debounceJob(ARGV[1], ARGV[13], ARGV[14],
  jobId, debounceKey, ARGV[11])
if debouncedJobId then
  return debouncedJobId
end

local debounceId = ARGV[13]

local optionalValues = {}

if debounceId ~= "" then
  table.insert(optionalValues, "deid")
  table.insert(optionalValues, debounceId)
end

    -- Store the job.
rcall("HMSET", jobIdKey, "name", ARGV[3], "data", ARGV[4], "opts", opts, "timestamp",
  ARGV[6], "delay", ARGV[7], "priority", ARGV[9], unpack(optionalValues))

-- Check if job is delayed
local delayedTimestamp = tonumber(ARGV[8])
if(delayedTimestamp ~= 0) then
  local timestamp = delayedTimestamp * 0x1000 + bit.band(jobCounter, 0xfff)
  rcall("ZADD", KEYS[5], timestamp, jobId)
  rcall("PUBLISH", KEYS[5], delayedTimestamp)
else
  local target

  -- Whe check for the meta-paused key to decide if we are paused or not
  -- (since an empty list and !EXISTS are not really the same)
  local target, paused = getTargetQueueList(KEYS[3], KEYS[1], KEYS[2])

  -- Standard or priority add
  local priority = tonumber(ARGV[9])
  if priority == 0 then
      -- LIFO or FIFO
    rcall(ARGV[10], target, jobId)
  else
    addJobWithPriority(KEYS[6], priority, jobId, target)
  end

  -- Emit waiting event (wait..ing@token)
  rcall("PUBLISH", KEYS[1] .. "ing@" .. ARGV[11], jobId)
end

return jobId .. "" -- convert to string


================================================
FILE: lib/commands/addLog-2.lua
================================================
--[[
  Add job log

  Input:
    KEYS[1] job id key
    KEYS[2] job logs key

    ARGV[1] id
    ARGV[2] log
    ARGV[3] keepLogs

  Output:
    -1 - Missing job.
]]
local rcall = redis.call

if rcall("EXISTS", KEYS[1]) == 1 then -- // Make sure job exists
  local logCount = rcall("RPUSH", KEYS[2], ARGV[2])

  if ARGV[3] ~= '' then
    local keepLogs = tonumber(ARGV[3])
    rcall("LTRIM", KEYS[2], -keepLogs, -1)

    return math.min(keepLogs, logCount)
  end

  return logCount
else
  return -1
end


================================================
FILE: lib/commands/cleanJobsInSet-3.lua
================================================
--[[
  Remove jobs from the specific set.

  Input:
    KEYS[1]  set key,
    KEYS[2]  priority key
    KEYS[3]  rate limiter key

    ARGV[1]  prefix key
    ARGV[2]  maxTimestamp
    ARGV[3]  limit the number of jobs to be removed. 0 is unlimited
    ARGV[4]  set name, can be any of 'wait', 'active', 'paused', 'delayed', 'completed', or 'failed'
]]

local setKey = KEYS[1]
local priorityKey = KEYS[2]
local rateLimiterKey = KEYS[3]

local prefixKey = ARGV[1]
local maxTimestamp = ARGV[2]
local limitStr = ARGV[3]
local setName = ARGV[4]

local isList = false
local rcall = redis.call

-- Includes
--- @include "includes/removeDebounceKey"

if setName == "wait" or setName == "active" or setName == "paused" then
  isList = true
end

-- We use ZRANGEBYSCORE to make the case where we're deleting a limited number
-- of items in a sorted set only run a single iteration. If we simply used
-- ZRANGE, we may take a long time traversing through jobs that are within the
-- grace period.
local function shouldUseZRangeByScore(isList, limit)
  return not isList and limit > 0
end

local function getJobs(setKey, isList, rangeStart, rangeEnd, maxTimestamp, limit)
  if isList then
    return rcall("LRANGE", setKey, rangeStart, rangeEnd)
  elseif shouldUseZRangeByScore(isList, limit) then
    return rcall("ZRANGEBYSCORE", setKey, 0, maxTimestamp, "LIMIT", 0, limit)
  else
    return rcall("ZRANGE", setKey, rangeStart, rangeEnd)
  end
end

local limit = tonumber(limitStr)
local rangeStart = 0
local rangeEnd = -1

-- If we're only deleting _n_ items, avoid retrieving all items
-- for faster performance
--
-- Start from the tail of the list, since that's where oldest elements
-- are generally added for FIFO lists
if limit > 0 then
  rangeStart = -1 - limit + 1
  rangeEnd = -1
end

local jobIds = getJobs(setKey, isList, rangeStart, rangeEnd, maxTimestamp, limit)
local deleted = {}
local deletedCount = 0
local jobTS

-- Run this loop:
-- - Once, if limit is -1 or 0
-- - As many times as needed if limit is positive
while ((limit <= 0 or deletedCount < limit) and next(jobIds, nil) ~= nil) do
  local jobIdsLen = #jobIds
  for i, jobId in ipairs(jobIds) do
    if limit > 0 and deletedCount >= limit then
      break
    end

    local jobKey = prefixKey .. jobId
    if (rcall("EXISTS", jobKey .. ":lock") == 0) then
      -- Find the right timestamp of the job to compare to maxTimestamp:
      -- * finishedOn says when the job was completed, but it isn't set unless the job has actually completed
      -- * processedOn represents when the job was last attempted, but it doesn't get populated until the job is first tried
      -- * timestamp is the original job submission time
      -- Fetch all three of these (in that order) and use the first one that is set so that we'll leave jobs that have been active within the grace period:
      for _, ts in ipairs(rcall("HMGET", jobKey, "finishedOn", "processedOn", "timestamp")) do
        if (ts) then
          jobTS = ts
          break
        end
      end
      if (not jobTS or jobTS < maxTimestamp) then
        if isList then
          -- Job ids can't be the empty string. Use the empty string as a
          -- deletion marker. The actual deletion will occur at the end of the
          -- script.
          rcall("LSET", setKey, rangeEnd - jobIdsLen + i, "")
        else
          rcall("ZREM", setKey, jobId)
        end
        rcall("ZREM", priorityKey, jobId)

        if setName ~= "completed" and setName ~= "failed" then
          removeDebounceKey(prefixKey, jobKey)
        end

        rcall("DEL", jobKey)
        rcall("DEL", jobKey .. ":logs")

        -- delete keys related to rate limiter
        -- NOTE: this code is unncessary for other sets than wait, paused and delayed.
        local limiterIndexTable = rateLimiterKey .. ":index"
        local limitedSetKey = rcall("HGET", limiterIndexTable, jobId)

        if limitedSetKey then
          rcall("SREM", limitedSetKey, jobId)
          rcall("HDEL", limiterIndexTable, jobId)
        end

        deletedCount = deletedCount + 1
        table.insert(deleted, jobId)
      end
    end
  end

  -- If we didn't have a limit or used the single-iteration ZRANGEBYSCORE
  -- function, return immediately. We should have deleted all the jobs we can
  if limit <= 0 or shouldUseZRangeByScore(isList, limit) then
    break
  end

  if deletedCount < limit then
    -- We didn't delete enough. Look for more to delete
    rangeStart = rangeStart - limit
    rangeEnd = rangeEnd - limit
    jobIds = getJobs(setKey, isList, rangeStart, rangeEnd, maxTimestamp, limit)
  end
end

if isList then
  rcall("LREM", setKey, 0, "")
end

return deleted


================================================
FILE: lib/commands/extendLock-2.lua
================================================
--[[
  Extend lock and removes the job from the stalled set.

  Input:
    KEYS[1] 'lock',
    KEYS[2] 'stalled'

    ARGV[1]  token
    ARGV[2]  lock duration in milliseconds
    ARGV[3]  jobid

  Output:
    "1" if lock extended succesfully.
]]
local rcall = redis.call
if rcall("GET", KEYS[1]) == ARGV[1] then
  if rcall("SET", KEYS[1], ARGV[1], "PX", ARGV[2]) then
    rcall("SREM", KEYS[2], ARGV[3])
    return 1
  end
end
return 0


================================================
FILE: lib/commands/getCountsPerPriority-4.lua
================================================
--[[
  Get counts per provided states

    Input:
      KEYS[1] wait key
      KEYS[2] paused key
      KEYS[3] meta-paused key
      KEYS[4] priority key

      ARGV[1...] priorities
]]
local rcall = redis.call
local results = {}
local prioritizedKey = KEYS[4]

-- Includes
--- @include "includes/getTargetQueueList"

for i = 1, #ARGV do
  local priority = tonumber(ARGV[i])
  if priority == 0 then
    local target = getTargetQueueList(KEYS[3], KEYS[1], KEYS[2])
    local count = rcall("LLEN", target) - rcall("ZCARD", prioritizedKey)
    if count < 0 then
      -- considering when last waiting job is moved to active before
      -- removing priority reference
      results[#results+1] = 0
    else
      results[#results+1] = count
    end
  else
    results[#results+1] = rcall("ZCOUNT", prioritizedKey,
      priority, priority)
  end
end

return results


================================================
FILE: lib/commands/includes/addJobWithPriority.lua
================================================
--[[
  Function to add job considering priority.
]]

local function addJobWithPriority(priorityKey, priority, jobId, targetKey)
  rcall("ZADD", priorityKey, priority, jobId)
  local count = rcall("ZCOUNT", priorityKey, 0, priority)

  local len = rcall("LLEN", targetKey)
  local id = rcall("LINDEX", targetKey, len - (count - 1))
  if id then
    rcall("LINSERT", targetKey, "BEFORE", id, jobId)
  else
    rcall("RPUSH", targetKey, jobId)
  end
end


================================================
FILE: lib/commands/includes/batches.lua
================================================
--[[
  Function to loop in batches.
  Just a bit of warning, some commands as ZREM
  could receive a maximum of 7000 parameters per call.
]]

local function batches(n, batchSize)
  local i = 0

  return function()
    local from = i * batchSize + 1
    i = i + 1
    if (from <= n) then
      local to = math.min(from + batchSize - 1, n)
      return from, to
    end
  end
end


================================================
FILE: lib/commands/includes/collectMetrics.lua
================================================
--[[
  Functions to collect metrics based on a current and previous count of jobs.
  Granualarity is fixed at 1 minute.
]]

-- Includes
--- @include "batches"

local function collectMetrics(metaKey, dataPointsList, maxDataPoints, timestamp)
    -- Increment current count
    local count = rcall("HINCRBY", metaKey, "count", 1) - 1

    -- Compute how many data points we need to add to the list, N.
    local prevTS = rcall("HGET", metaKey, "prevTS")

    if not prevTS then
        -- If prevTS is nil, set it to the current timestamp
        rcall("HSET", metaKey, "prevTS", timestamp, "prevCount", 0)
        return
    end

    local N = math.min(math.floor(timestamp / 60000) - math.floor(prevTS / 60000), tonumber(maxDataPoints))

    if N > 0 then
        local delta = count - rcall("HGET", metaKey, "prevCount")
        -- If N > 1, add N-1 zeros to the list
        if N > 1 then
            local points = {}
            points[1] = delta
            for i = 2, N do points[i] = 0 end

            for from, to in batches(#points, 7000) do
                rcall("LPUSH", dataPointsList, unpack(points, from, to))
            end
        else
            -- LPUSH delta to the list
            rcall("LPUSH", dataPointsList, delta)
        end

        -- LTRIM to keep list to its max size
        rcall("LTRIM", dataPointsList, 0, maxDataPoints - 1)

        -- update prev count with current count
        rcall("HSET", metaKey, "prevCount", count, "prevTS", timestamp)
    end
end


================================================
FILE: lib/commands/includes/debounceJob.lua
================================================
--[[
  Function to debounce a job.
]]

local function debounceJob(prefixKey, debounceId, ttl, jobId, debounceKey, token)
  if debounceId ~= "" then
    local debounceKeyExists
    if ttl ~= "" then
      debounceKeyExists = not rcall('SET', debounceKey, jobId, 'PX', ttl, 'NX')
    else
      debounceKeyExists = not rcall('SET', debounceKey, jobId, 'NX')
    end
    if debounceKeyExists then
      local currentDebounceJobId = rcall('GET', debounceKey)
      rcall("PUBLISH", prefixKey .. "debounced@" .. token, currentDebounceJobId)

      return currentDebounceJobId
    end
  end
end

================================================
FILE: lib/commands/includes/getTargetQueueList.lua
================================================
--[[
  Function to check for the meta.paused key to decide if we are paused or not
  (since an empty list and !EXISTS are not really the same).
]]

local function getTargetQueueList(queueMetaKey, waitKey, pausedKey)
  if rcall("EXISTS", queueMetaKey) ~= 1 then
    return waitKey, false
  else
    return pausedKey, true
  end
end


================================================
FILE: lib/commands/includes/removeDebounceKey.lua
================================================

--[[
  Function to remove debounce key.
]]

local function removeDebounceKey(prefixKey, jobKey)
  local debounceId = rcall("HGET", jobKey, "deid")
  if debounceId then
    local debounceKey = prefixKey .. "de:" .. debounceId
    rcall("DEL", debounceKey)
  end
end


================================================
FILE: lib/commands/includes/remove
Download .txt
gitextract_f80qykri/

├── .editorconfig
├── .eslintrc.yml
├── .github/
│   ├── issue_template.md
│   ├── stale.yml
│   └── workflows/
│       ├── codeql-analysis.yml
│       ├── node.js.yml
│       └── release.yml
├── .gitignore
├── .mocharc.json
├── .npmignore
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE.md
├── MIGRATION.md
├── PATTERNS.md
├── README.md
├── REFERENCE.md
├── commandTransform.js
├── commitlint.config.js
├── docker-compose.yml
├── docs/
│   ├── README.md
│   └── _config.yml
├── generateRawScripts.js
├── index.d.ts
├── index.js
├── lib/
│   ├── backoffs.js
│   ├── commands/
│   │   ├── addJob-6.lua
│   │   ├── addLog-2.lua
│   │   ├── cleanJobsInSet-3.lua
│   │   ├── extendLock-2.lua
│   │   ├── getCountsPerPriority-4.lua
│   │   ├── includes/
│   │   │   ├── addJobWithPriority.lua
│   │   │   ├── batches.lua
│   │   │   ├── collectMetrics.lua
│   │   │   ├── debounceJob.lua
│   │   │   ├── getTargetQueueList.lua
│   │   │   ├── removeDebounceKey.lua
│   │   │   ├── removeDebounceKeyIfNeeded.lua
│   │   │   └── removeLock.lua
│   │   ├── index.js
│   │   ├── isFinished-2.lua
│   │   ├── isJobInList-1.lua
│   │   ├── moveStalledJobsToWait-7.lua
│   │   ├── moveToActive-8.lua
│   │   ├── moveToDelayed-4.lua
│   │   ├── moveToFinished-9.lua
│   │   ├── obliterate-2.lua
│   │   ├── pause-5.lua
│   │   ├── promote-5.lua
│   │   ├── releaseLock-1.lua
│   │   ├── removeJob-11.lua
│   │   ├── removeJobs-8.lua
│   │   ├── removeRepeatable-2.lua
│   │   ├── reprocessJob-6.lua
│   │   ├── retryJob-7.lua
│   │   ├── retryJobs-5.lua
│   │   ├── saveStacktrace-1.lua
│   │   ├── script-loader.js
│   │   ├── takeLock-1.lua
│   │   ├── updateData-1.lua
│   │   ├── updateDelaySet-6.lua
│   │   └── updateProgress-2.lua
│   ├── errors.js
│   ├── getters.js
│   ├── job.js
│   ├── p-timeout.js
│   ├── process/
│   │   ├── child-pool.js
│   │   ├── master.js
│   │   ├── sandbox.js
│   │   └── utils.js
│   ├── queue.js
│   ├── repeatable.js
│   ├── scripts.js
│   ├── timer-manager.js
│   ├── utils.js
│   └── worker.js
├── package.json
├── support/
│   └── logo.sketch
└── test/
    ├── .eslintrc.yml
    ├── fixtures/
    │   ├── fixture_processor.js
    │   ├── fixture_processor_bar.js
    │   ├── fixture_processor_broken.js
    │   ├── fixture_processor_callback.js
    │   ├── fixture_processor_callback_fail.js
    │   ├── fixture_processor_crash.js
    │   ├── fixture_processor_data.js
    │   ├── fixture_processor_discard.js
    │   ├── fixture_processor_exit.js
    │   ├── fixture_processor_fail.js
    │   ├── fixture_processor_foo.js
    │   ├── fixture_processor_progress.js
    │   └── fixture_processor_slow.js
    ├── test_child-pool.js
    ├── test_connection.js
    ├── test_events.js
    ├── test_getters.js
    ├── test_job.js
    ├── test_metrics.js
    ├── test_obliterate.js
    ├── test_pause.js
    ├── test_queue.js
    ├── test_rate_limiter.js
    ├── test_repeat.js
    ├── test_sandboxed_process.js
    ├── test_when_current_jobs_finished.js
    ├── test_worker.js
    └── utils.js
Download .txt
SYMBOL INDEX (152 symbols across 20 files)

FILE: generateRawScripts.js
  class RawScriptLoader (line 9) | class RawScriptLoader extends ScriptLoader {
    method transpileScripts (line 15) | async transpileScripts(pathname, writeDir) {

FILE: index.d.ts
  type RateLimiter (line 51) | interface RateLimiter {
  type QueueOptions (line 62) | interface QueueOptions {
  type MetricsOpts (line 92) | interface MetricsOpts {
  type AdvancedSettings (line 96) | interface AdvancedSettings {
  type DoneCallback (line 147) | type DoneCallback = (error?: Error | null, value?: any) => void;
  type JobId (line 149) | type JobId = number | string;
  type ProcessCallbackFunction (line 151) | type ProcessCallbackFunction<T> = (job: Job<T>, done: DoneCallback) => v...
  type ProcessPromiseFunction (line 152) | type ProcessPromiseFunction<T> = (job: Job<T>) => Promise<void>;
  type Job (line 154) | interface Job<T = any> {
  type JobStatus (line 356) | type JobStatus =
  type JobStatusClean (line 363) | type JobStatusClean =
  type BackoffOptions (line 371) | interface BackoffOptions {
  type RepeatOptions (line 388) | interface RepeatOptions {
  type CronRepeatOptions (line 410) | interface CronRepeatOptions extends RepeatOptions {
  type EveryRepeatOptions (line 422) | interface EveryRepeatOptions extends RepeatOptions {
  type DebounceOptions (line 429) | interface DebounceOptions {
  type JobOptions (line 440) | interface JobOptions {
  type KeepJobsOptions (line 531) | interface KeepJobsOptions {
  type JobCounts (line 543) | interface JobCounts {
  type JobInformation (line 551) | interface JobInformation {
  type Queue (line 562) | interface Queue<T = any> extends EventEmitter {
  type EventCallback (line 1100) | type EventCallback = () => void;
  type ErrorEventCallback (line 1102) | type ErrorEventCallback = (error: Error) => void;
  type JobPromise (line 1104) | interface JobPromise {
  type ActiveEventCallback (line 1111) | type ActiveEventCallback<T = any> = (
  type StalledEventCallback (line 1116) | type StalledEventCallback<T = any> = (job: Job<T>) => void;
  type ProgressEventCallback (line 1118) | type ProgressEventCallback<T = any> = (job: Job<T>, progress: any) => void;
  type CompletedEventCallback (line 1120) | type CompletedEventCallback<T = any> = (job: Job<T>, result: any) => void;
  type FailedEventCallback (line 1122) | type FailedEventCallback<T = any> = (job: Job<T>, error: Error) => void;
  type CleanedEventCallback (line 1124) | type CleanedEventCallback<T = any> = (
  type RemovedEventCallback (line 1129) | type RemovedEventCallback<T = any> = (job: Job<T>) => void;
  type WaitingEventCallback (line 1131) | type WaitingEventCallback = (jobId: JobId) => void;

FILE: lib/backoffs.js
  method fixed (line 6) | fixed(delay) {
  method exponential (line 12) | exponential(delay) {
  function lookupStrategy (line 19) | function lookupStrategy(backoff, customStrategies) {
  method normalize (line 34) | normalize(backoff) {
  method calculate (line 45) | calculate(backoff, attemptsMade, customStrategies, err, strategyOptions) {

FILE: lib/commands/script-loader.js
  class ScriptLoaderError (line 14) | class ScriptLoaderError extends Error {
    method constructor (line 19) | constructor(message, path, stack = [], line, position = 0) {
  class ScriptLoader (line 35) | class ScriptLoader {
    method constructor (line 36) | constructor() {
    method addPathMapping (line 56) | addPathMapping(name, mappedPath) {
    method resolvePath (line 80) | resolvePath(scriptName, stack = []) {
    method resolveDependencies (line 110) | async resolveDependencies(file, cache, isInclude = false, stack = []) {
    method parseScript (line 279) | async parseScript(filename, content, cache) {
    method interpolate (line 303) | interpolate(file, processed) {
    method loadCommand (line 328) | async loadCommand(filename, cache) {
    method loadScripts (line 359) | async loadScripts(dir, cache) {
    method load (line 399) | async load(client, pathname, cache) {
    method clearCache (line 423) | clearCache() {
  function ensureExt (line 428) | function ensureExt(filename, ext = 'lua') {
  function splitFilename (line 439) | function splitFilename(filePath) {
  function getPkgJsonDir (line 448) | function getPkgJsonDir() {
  function getCallerFile (line 465) | function getCallerFile() {
  function sha1 (line 493) | function sha1(data) {
  function getPathHash (line 499) | function getPathHash(normalizedPath) {
  function replaceAll (line 503) | function replaceAll(str, find, replace) {
  function removeEmptyLines (line 507) | function removeEmptyLines(str) {

FILE: lib/getters.js
  function parseTypeArg (line 262) | function parseTypeArg(args) {

FILE: lib/job.js
  constant FINISHED_WATCHDOG (line 10) | const FINISHED_WATCHDOG = 5000;
  constant DEFAULT_JOB_NAME (line 11) | const DEFAULT_JOB_NAME = '__default__';
  function setDefaultOpts (line 63) | function setDefaultOpts(opts) {
  function addJob (line 79) | function addJob(queue, client, job) {
  function getTraces (line 654) | function getTraces(stacktrace) {
  function getReturnValue (line 664) | function getReturnValue(_value) {

FILE: lib/p-timeout.js
  class TimeoutError (line 5) | class TimeoutError extends Error {
    method constructor (line 6) | constructor(message) {

FILE: lib/process/child-pool.js
  constant CHILD_KILL_TIMEOUT (line 9) | const CHILD_KILL_TIMEOUT = 30000;
  function initChild (line 113) | async function initChild(child, processFile) {
  function ChildPoolSingleton (line 131) | function ChildPoolSingleton(isSharedChildPool = false) {

FILE: lib/process/master.js
  function waitForCurrentJobAndExit (line 32) | async function waitForCurrentJobAndExit() {
  function wrapJob (line 141) | function wrapJob(job) {

FILE: lib/process/utils.js
  function hasProcessExited (line 3) | function hasProcessExited(child) {
  function onExitOnce (line 7) | function onExitOnce(child) {
  function killAsync (line 23) | function killAsync(child, signal, timeoutMs) {

FILE: lib/queue.js
  constant MINIMUM_REDIS_VERSION (line 55) | const MINIMUM_REDIS_VERSION = '2.8.18';
  function redisClientGetter (line 289) | function redisClientGetter(queue, options, initCallback) {
  function redisOptsFromUrl (line 334) | function redisOptsFromUrl(urlString) {
  function redisClientDisconnect (line 569) | async function redisClientDisconnect(client) {
  function getRedisVersion (line 1396) | function getRedisVersion(client) {
  function jobIdForGroup (line 1408) | function jobIdForGroup(limiter, opts, data) {

FILE: lib/repeatable.js
  function getRepeatJobId (line 185) | function getRepeatJobId(name, jobId, nextMillis, namespace) {
  function getRepeatKey (line 189) | function getRepeatKey(name, repeat, jobId) {
  function getNextMillis (line 199) | function getNextMillis(millis, opts) {
  function md5 (line 231) | function md5(str) {

FILE: lib/scripts.js
  method isJobInList (line 18) | isJobInList(client, listKey, jobId) {
  method addJob (line 24) | addJob(client, queue, job, opts) {
  method pause (line 55) | pause(queue, pause) {
  method addLog (line 73) | async addLog(queue, jobId, logRow, keepLogs) {
  method getCountsPerPriorityArgs (line 89) | getCountsPerPriorityArgs(queue, priorities) {
  method getCountsPerPriority (line 102) | async getCountsPerPriority(queue, priorities) {
  method moveToActive (line 109) | moveToActive(queue, jobId) {
  method updateProgress (line 139) | updateProgress(job, progress) {
  method updateData (line 159) | updateData(job, data) {
  method saveStacktraceArgs (line 169) | saveStacktraceArgs(
  method retryJobsArgs (line 181) | retryJobsArgs(queue, count) {
  method retryJobs (line 195) | async retryJobs(queue, count = 1000) {
  method moveToFinishedArgs (line 203) | moveToFinishedArgs(
  method moveToFinished (line 255) | moveToFinished(
  method finishedErrors (line 284) | finishedErrors(code, jobId, command, state) {
  method moveToCompleted (line 302) | moveToCompleted(
  method moveToFailedArgs (line 320) | moveToFailedArgs(job, failedReason, removeOnFailed, ignoreLock) {
  method moveToFailed (line 332) | moveToFailed(job, failedReason, removeOnFailed, ignoreLock) {
  method isFinished (line 342) | isFinished(job) {
  method moveToDelayedArgs (line 350) | moveToDelayedArgs(queue, jobId, timestamp, ignoreLock) {
  method moveToDelayed (line 376) | moveToDelayed(queue, jobId, timestamp, ignoreLock) {
  method remove (line 396) | remove(queue, jobId) {
  method removeWithPattern (line 413) | async removeWithPattern(queue, pattern) {
  method extendLock (line 438) | extendLock(queue, jobId, duration) {
  method releaseLock (line 448) | releaseLock(queue, jobId) {
  method takeLock (line 455) | takeLock(queue, job) {
  method updateDelaySet (line 467) | updateDelaySet(queue, delayedTimestamp) {
  method promote (line 481) | promote(queue, jobId) {
  method moveUnlockedJobsToWait (line 503) | moveUnlockedJobsToWait(queue) {
  method cleanJobsInSet (line 522) | cleanJobsInSet(queue, set, ts, limit) {
  method retryJobArgs (line 534) | retryJobArgs(job, ignoreLock) {
  method reprocessJob (line 564) | reprocessJob(job, options) {
  method obliterate (line 586) | obliterate(queue, opts) {
  function array2obj (line 608) | function array2obj(arr) {
  function raw2jobData (line 616) | function raw2jobData(raw) {

FILE: lib/timer-manager.js
  function TimerManager (line 57) | function TimerManager() {

FILE: lib/utils.js
  function tryCatch (line 3) | function tryCatch(fn, ctx, args) {
  function isRedisReady (line 16) | function isRedisReady(client) {

FILE: test/test_connection.js
  method createClient (line 27) | createClient(type) {
  method createClient (line 132) | createClient(type) {

FILE: test/test_metrics.js
  constant ONE_SECOND (line 8) | const ONE_SECOND = 1000;
  constant ONE_MINUTE (line 9) | const ONE_MINUTE = 60 * ONE_SECOND;
  constant ONE_HOUR (line 10) | const ONE_HOUR = 60 * ONE_MINUTE;

FILE: test/test_queue.js
  function checkStatus (line 49) | function checkStatus(status) {
  method createClient (line 308) | createClient(type, opts) {
  function testRemoveOnFinish (line 497) | async function testRemoveOnFinish(opts, expectedCount, fail) {
  method custom (line 2826) | custom(attemptsMade) {
  method custom (line 2864) | custom(attemptsMade, err, strategyOptions) {
  method custom (line 2905) | custom() {
  function CustomError (line 2940) | function CustomError() {}
  method custom (line 2946) | custom(attemptsMade, err) {
  method custom (line 2988) | async custom() {

FILE: test/test_repeat.js
  constant ONE_SECOND (line 10) | const ONE_SECOND = 1000;
  constant ONE_MINUTE (line 11) | const ONE_MINUTE = 60 * ONE_SECOND;
  constant ONE_HOUR (line 12) | const ONE_HOUR = 60 * ONE_MINUTE;
  constant ONE_DAY (line 13) | const ONE_DAY = 24 * ONE_HOUR;
  constant MAX_INT (line 14) | const MAX_INT = 2147483647;
  function nextTick (line 369) | function nextTick() {

FILE: test/utils.js
  constant STD_QUEUE_NAME (line 4) | const STD_QUEUE_NAME = 'test queue';
  function simulateDisconnect (line 11) | function simulateDisconnect(queue) {
  function buildQueue (line 16) | function buildQueue(name, options) {
  function newQueue (line 23) | function newQueue(name, opts) {
  function cleanupQueue (line 28) | function cleanupQueue(queue) {
  function cleanupQueues (line 32) | function cleanupQueues() {
  function sleep (line 44) | function sleep(ms) {
Condensed preview — 108 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (615K chars).
[
  {
    "path": ".editorconfig",
    "chars": 254,
    "preview": "; EditorConfig file: http://EditorConfig.org\n; Install the \"EditorConfig\" plugin into Sublime Text to use\n\nroot = true\n\n"
  },
  {
    "path": ".eslintrc.yml",
    "chars": 735,
    "preview": "env:\n  node: true\n\nparserOptions:\n  ecmaVersion: 2018\n\nextends:\n  - eslint:recommended\n  - plugin:mocha/recommended\n  - "
  },
  {
    "path": ".github/issue_template.md",
    "chars": 717,
    "preview": "<!--\nYou may report several types of issues. Bug reports, enhancements or questions.\nFor bug reports however you are req"
  },
  {
    "path": ".github/stale.yml",
    "chars": 723,
    "preview": "# Number of days of inactivity before an issue becomes stale\ndaysUntilStale: 60\n# Number of days of inactivity before a "
  },
  {
    "path": ".github/workflows/codeql-analysis.yml",
    "chars": 2332,
    "preview": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# Y"
  },
  {
    "path": ".github/workflows/node.js.yml",
    "chars": 1069,
    "preview": "# This workflow will do a clean install of node dependencies, build the source code and run tests across different versi"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 728,
    "preview": "name: Release\non:\n  push:\n    branches:\n      - develop\npermissions: {}\njobs:\n  release:\n    permissions:\n      contents"
  },
  {
    "path": ".gitignore",
    "chars": 93,
    "preview": "node_modules\ntmp\ncoverage\n*.rdb\n.vscode\npackage-lock.json\n.nyc_output\nrawScripts\nlib/scripts\n"
  },
  {
    "path": ".mocharc.json",
    "chars": 60,
    "preview": "{\n  \"timeout\": 5000,\n  \"reporter\": \"spec\",\n  \"exit\": true\n}\n"
  },
  {
    "path": ".npmignore",
    "chars": 241,
    "preview": "node_modules\ntmp\ntest\nbugs\ndocs\nsupport\n.github\n.editorconfig\n.eslintrc.yml\n.travis.yml\n.gitignore\n*.md\ncommitlint.confi"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 48107,
    "preview": "## [4.16.5](https://github.com/OptimalBits/bull/compare/v4.16.4...v4.16.5) (2024-12-18)\n\n\n### Bug Fixes\n\n* upgrade cron-"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 3219,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 316,
    "preview": "Release process\n---------------\n\nFirst, update `CHANGELOG.md` with the release number about to be released.\n\n    npm out"
  },
  {
    "path": "LICENSE.md",
    "chars": 1130,
    "preview": "\nLicense\n-------\n\n(The MIT License)\n\nCopyright &copy; 2013-2018 Manuel Astudillo <manuel@optimalbits.com>\n\nPermission is"
  },
  {
    "path": "MIGRATION.md",
    "chars": 1578,
    "preview": "# Migration from 2.x to 3.0.0\n\nAlthough version 3.0 is almost backwards compatible with 2.x, there are some important ch"
  },
  {
    "path": "PATTERNS.md",
    "chars": 9500,
    "preview": "\nPatterns\n========\n\nHere are a few examples of useful patterns that are often implemented with Bull:\n\n- [Message Queue]("
  },
  {
    "path": "README.md",
    "chars": 18667,
    "preview": "\n<div align=\"center\">\n  <br/>\n  <img src=\"./support/logo@2x.png\" width=\"300\" />\n  <br/>\n  <br/>\n  <p>\n    The fastest, m"
  },
  {
    "path": "REFERENCE.md",
    "chars": 38762,
    "preview": "# Reference\n\n- [Queue](#queue)\n\n  - [Queue#process](#queueprocess)\n  - [Queue#add](#queueadd)\n  - [Queue#addBulk](#queue"
  },
  {
    "path": "commandTransform.js",
    "chars": 1885,
    "preview": "'use strict';\nconst path = require('path');\nconst fs = require('fs');\nconst { argv } = require('process');\n\nconst readFi"
  },
  {
    "path": "commitlint.config.js",
    "chars": 82,
    "preview": "'use strict';\n\nmodule.exports = { extends: ['@commitlint/config-conventional'] };\n"
  },
  {
    "path": "docker-compose.yml",
    "chars": 117,
    "preview": "version: '3.2'\nservices:\n  redis:\n    image: redis:6.2-alpine\n    container_name: cache\n    ports:\n      - 6379:6379\n"
  },
  {
    "path": "docs/README.md",
    "chars": 13412,
    "preview": "<div align=\"center\" style=\"padding-bottom: 50px;\">\n  <br/>\n  <img src=\"https://raw.githubusercontent.com/OptimalBits/bul"
  },
  {
    "path": "docs/_config.yml",
    "chars": 59,
    "preview": "theme: jekyll-theme-minimal\ntitle: Welcome to Bull's Guide\n"
  },
  {
    "path": "generateRawScripts.js",
    "chars": 1271,
    "preview": "'use strict';\nconst { ScriptLoader } = require('./lib/commands');\nconst path = require('path');\nconst fs = require('fs')"
  },
  {
    "path": "index.d.ts",
    "chars": 35579,
    "preview": "// Type definitions for bull 3.15\n// Project: https://github.com/OptimalBits/bull\n// Definitions by: Bruno Grieder <http"
  },
  {
    "path": "index.js",
    "chars": 146,
    "preview": "'use strict';\n\nmodule.exports = require('./lib/queue');\nmodule.exports.Job = require('./lib/job');\nmodule.exports.utils "
  },
  {
    "path": "lib/backoffs.js",
    "chars": 1214,
    "preview": "'use strict';\n\nconst _ = require('lodash');\n\nconst builtinStrategies = {\n  fixed(delay) {\n    return function() {\n      "
  },
  {
    "path": "lib/commands/addJob-6.lua",
    "chars": 3034,
    "preview": "--[[\n  Adds a job to the queue by doing the following:\n    - Increases the job counter if needed.\n    - Creates a new jo"
  },
  {
    "path": "lib/commands/addLog-2.lua",
    "chars": 503,
    "preview": "--[[\n  Add job log\n\n  Input:\n    KEYS[1] job id key\n    KEYS[2] job logs key\n\n    ARGV[1] id\n    ARGV[2] log\n    ARGV[3]"
  },
  {
    "path": "lib/commands/cleanJobsInSet-3.lua",
    "chars": 4679,
    "preview": "--[[\n  Remove jobs from the specific set.\n\n  Input:\n    KEYS[1]  set key,\n    KEYS[2]  priority key\n    KEYS[3]  rate li"
  },
  {
    "path": "lib/commands/extendLock-2.lua",
    "chars": 437,
    "preview": "--[[\n  Extend lock and removes the job from the stalled set.\n\n  Input:\n    KEYS[1] 'lock',\n    KEYS[2] 'stalled'\n\n    AR"
  },
  {
    "path": "lib/commands/getCountsPerPriority-4.lua",
    "chars": 864,
    "preview": "--[[\n  Get counts per provided states\n\n    Input:\n      KEYS[1] wait key\n      KEYS[2] paused key\n      KEYS[3] meta-pau"
  },
  {
    "path": "lib/commands/includes/addJobWithPriority.lua",
    "chars": 451,
    "preview": "--[[\n  Function to add job considering priority.\n]]\n\nlocal function addJobWithPriority(priorityKey, priority, jobId, tar"
  },
  {
    "path": "lib/commands/includes/batches.lua",
    "chars": 378,
    "preview": "--[[\n  Function to loop in batches.\n  Just a bit of warning, some commands as ZREM\n  could receive a maximum of 7000 par"
  },
  {
    "path": "lib/commands/includes/collectMetrics.lua",
    "chars": 1496,
    "preview": "--[[\n  Functions to collect metrics based on a current and previous count of jobs.\n  Granualarity is fixed at 1 minute.\n"
  },
  {
    "path": "lib/commands/includes/debounceJob.lua",
    "chars": 588,
    "preview": "--[[\n  Function to debounce a job.\n]]\n\nlocal function debounceJob(prefixKey, debounceId, ttl, jobId, debounceKey, token)"
  },
  {
    "path": "lib/commands/includes/getTargetQueueList.lua",
    "chars": 331,
    "preview": "--[[\n  Function to check for the meta.paused key to decide if we are paused or not\n  (since an empty list and !EXISTS ar"
  },
  {
    "path": "lib/commands/includes/removeDebounceKey.lua",
    "chars": 266,
    "preview": "\n--[[\n  Function to remove debounce key.\n]]\n\nlocal function removeDebounceKey(prefixKey, jobKey)\n  local debounceId = rc"
  },
  {
    "path": "lib/commands/includes/removeDebounceKeyIfNeeded.lua",
    "chars": 327,
    "preview": "--[[\n  Function to remove debounce key if needed.\n]]\n\nlocal function removeDebounceKeyIfNeeded(prefixKey, debounceId)\n  "
  },
  {
    "path": "lib/commands/includes/removeLock.lua",
    "chars": 468,
    "preview": "local function removeLock(jobKey, stalledKey, token, jobId)\n  if token ~= \"0\" then\n    local lockKey = jobKey .. ':lock'"
  },
  {
    "path": "lib/commands/index.js",
    "chars": 163,
    "preview": "'use strict';\nconst { ScriptLoader } = require('./script-loader');\n\nconst scriptLoader = new ScriptLoader();\n\nmodule.exp"
  },
  {
    "path": "lib/commands/isFinished-2.lua",
    "chars": 417,
    "preview": "--[[\n  Checks if a job is finished (.i.e. is in the completed or failed set)\n\n  Input: \n    KEYS[1] completed key\n    KE"
  },
  {
    "path": "lib/commands/isJobInList-1.lua",
    "chars": 375,
    "preview": "--[[\n      Checks if job is in a given list.\n\n      Input:\n        KEYS[1]\n        ARGV[1]\n\n      Output:\n        1 if e"
  },
  {
    "path": "lib/commands/moveStalledJobsToWait-7.lua",
    "chars": 4267,
    "preview": "--[[\n  Move stalled jobs to wait.\n\n    Input:\n      KEYS[1] 'stalled' (SET)\n      KEYS[2] 'wait',   (LIST)\n      KEYS[3]"
  },
  {
    "path": "lib/commands/moveToActive-8.lua",
    "chars": 4573,
    "preview": "--[[\n  Move next job to be processed to active, lock it and fetch its data. The job\n  may be delayed, in that case we ne"
  },
  {
    "path": "lib/commands/moveToDelayed-4.lua",
    "chars": 827,
    "preview": "--[[\n  Moves job from active to delayed set.\n\n  Input:\n    KEYS[1] active key\n    KEYS[2] delayed key\n    KEYS[3] job ke"
  },
  {
    "path": "lib/commands/moveToFinished-9.lua",
    "chars": 3964,
    "preview": "--[[\n  Move job from active to a finished status (completed or failed)\n  A job can only be moved to completed if it was "
  },
  {
    "path": "lib/commands/obliterate-2.lua",
    "chars": 3240,
    "preview": "--[[\n    Completely obliterates a queue and all of its contents\n     Input:\n\n        KEYS[1] meta-paused\n        KEYS[2]"
  },
  {
    "path": "lib/commands/pause-5.lua",
    "chars": 715,
    "preview": "--[[\n  Pauses or resumes a queue globably.\n\n   Input:\n      KEYS[1] 'wait' or 'paused''\n      KEYS[2] 'paused' or 'wait'"
  },
  {
    "path": "lib/commands/promote-5.lua",
    "chars": 981,
    "preview": "--[[\n  Promotes a job that is currently \"delayed\" to the \"waiting\" state\n\n     Input:\n      KEYS[1] 'delayed'\n      KEYS"
  },
  {
    "path": "lib/commands/releaseLock-1.lua",
    "chars": 319,
    "preview": "--[[\n  Release lock\n\n     Input:\n        KEYS[1] 'lock',\n      \n        ARGV[1]  token\n        ARGV[2]  lock duration in"
  },
  {
    "path": "lib/commands/removeJob-11.lua",
    "chars": 1427,
    "preview": "--[[\n    Remove a job from all the queues it may be in as well as all its data.\n    In order to be able to remove a job,"
  },
  {
    "path": "lib/commands/removeJobs-8.lua",
    "chars": 1842,
    "preview": "--[[\n    Remove all jobs matching a given pattern from all the queues they may be in as well as all its data.\n    In ord"
  },
  {
    "path": "lib/commands/removeRepeatable-2.lua",
    "chars": 474,
    "preview": "\n--[[\n  Removes a repeatable job\n  Input:\n    KEYS[1] repeat jobs key\n    KEYS[2] delayed jobs key\n\n    ARGV[1] repeat j"
  },
  {
    "path": "lib/commands/reprocessJob-6.lua",
    "chars": 1259,
    "preview": "--[[\n  Attempts to reprocess a job\n\n  Input:\n    KEYS[1] job key\n    KEYS[2] job lock key\n    KEYS[3] job state\n    KEYS"
  },
  {
    "path": "lib/commands/retryJob-7.lua",
    "chars": 1205,
    "preview": "--[[\n  Retries a failed job by moving it back to the wait queue.\n\n    Input:\n      KEYS[1] 'active',\n      KEYS[2] 'wait"
  },
  {
    "path": "lib/commands/retryJobs-5.lua",
    "chars": 1112,
    "preview": "--[[\n  Attempts to retry all failed jobs\n\n  Input:\n    KEYS[1] base key\n    KEYS[2] failed state key\n    KEYS[3] wait st"
  },
  {
    "path": "lib/commands/saveStacktrace-1.lua",
    "chars": 395,
    "preview": "--[[\n  Save stacktrace and failedReason.\n\n  Input:\n    KEYS[1] job key\n\n    ARGV[1]  stacktrace\n    ARGV[2]  failedReaso"
  },
  {
    "path": "lib/commands/script-loader.js",
    "chars": 14339,
    "preview": "'use strict';\nconst { createHash } = require('crypto');\nconst path = require('path');\nconst fs = require('fs');\nconst { "
  },
  {
    "path": "lib/commands/takeLock-1.lua",
    "chars": 295,
    "preview": "--[[\n  Takes a lock\n\n     Input:\n        KEYS[1] 'lock',\n      \n        ARGV[1]  token\n        ARGV[2]  lock duration in"
  },
  {
    "path": "lib/commands/updateData-1.lua",
    "chars": 284,
    "preview": "--[[\n  Update job data\n\n  Input:\n    KEYS[1] Job id key\n\n    ARGV[1] data\n\n  Output:\n    0 - OK\n   -1 - Missing job.\n]]\n"
  },
  {
    "path": "lib/commands/updateDelaySet-6.lua",
    "chars": 1506,
    "preview": "--[[\n  Updates the delay set, by picking a delayed job that should\n  be processed now.\n\n     Input:\n      KEYS[1] 'delay"
  },
  {
    "path": "lib/commands/updateProgress-2.lua",
    "chars": 417,
    "preview": "--[[\n  Update job progress\n\n     Input:\n        KEYS[1] Job id key\n        KEYS[2] progress event key\n      \n        ARG"
  },
  {
    "path": "lib/errors.js",
    "chars": 471,
    "preview": "'use strict';\n\nmodule.exports.Messages = {\n  RETRY_JOB_NOT_EXIST: \"Couldn't retry job: The job doesn't exist\",\n  RETRY_J"
  },
  {
    "path": "lib/getters.js",
    "chars": 7435,
    "preview": "'use strict';\n\nconst _ = require('lodash');\nconst Job = require('./job');\nconst scripts = require('./scripts');\n\nmodule."
  },
  {
    "path": "lib/job.js",
    "chars": 16948,
    "preview": "'use strict';\n\nconst _ = require('lodash');\nconst utils = require('./utils');\nconst scripts = require('./scripts');\ncons"
  },
  {
    "path": "lib/p-timeout.js",
    "chars": 1911,
    "preview": "// Extracted from p-timeout https://github.com/sindresorhus/p-timeout\n// as it is not commonjs compatible. This is versi"
  },
  {
    "path": "lib/process/child-pool.js",
    "chars": 3444,
    "preview": "'use strict';\n\nconst fork = require('child_process').fork;\nconst path = require('path');\nconst _ = require('lodash');\nco"
  },
  {
    "path": "lib/process/master.js",
    "chars": 4799,
    "preview": "/**\n * Master of child processes. Handles communication between the\n * processor and the main process.\n *\n */\n'use stric"
  },
  {
    "path": "lib/process/sandbox.js",
    "chars": 1720,
    "preview": "'use strict';\n\nconst { asyncSend } = require('./utils');\n\nmodule.exports = function(processFile, childPool) {\n  return f"
  },
  {
    "path": "lib/process/utils.js",
    "chars": 1547,
    "preview": "'use strict';\n\nfunction hasProcessExited(child) {\n  return !!(child.exitCode !== null || child.signalCode);\n}\n\nfunction "
  },
  {
    "path": "lib/queue.js",
    "chars": 38370,
    "preview": "'use strict';\n\nconst Redis = require('ioredis');\nconst EventEmitter = require('events');\n\nconst _ = require('lodash');\n\n"
  },
  {
    "path": "lib/repeatable.js",
    "chars": 6079,
    "preview": "'use strict';\n\nconst _ = require('lodash');\nconst parser = require('cron-parser');\nconst crypto = require('crypto');\n\nco"
  },
  {
    "path": "lib/scripts.js",
    "chars": 15123,
    "preview": "/**\n * Includes all the scripts needed by the queue and jobs.\n */\n\n'use strict';\n\nconst _ = require('lodash');\nconst msg"
  },
  {
    "path": "lib/timer-manager.js",
    "chars": 3466,
    "preview": "'use strict';\n\nconst _ = require('lodash');\nconst uuid = require('uuid');\n\n/**\n  Timer Manager\n\n  Keep track of timers t"
  },
  {
    "path": "lib/utils.js",
    "chars": 1622,
    "preview": "'use strict';\nconst errorObject = { value: null };\nfunction tryCatch(fn, ctx, args) {\n  try {\n    return fn.apply(ctx, a"
  },
  {
    "path": "lib/worker.js",
    "chars": 2117,
    "preview": "'use strict';\n\nconst utils = require('./utils');\nconst clientCommandMessageReg = /ERR unknown command ['`]\\s*client\\s*['"
  },
  {
    "path": "package.json",
    "chars": 3418,
    "preview": "{\n  \"name\": \"bull\",\n  \"version\": \"4.16.5\",\n  \"description\": \"Job manager\",\n  \"engines\": {\n    \"node\": \">=12\"\n  },\n  \"mai"
  },
  {
    "path": "test/.eslintrc.yml",
    "chars": 95,
    "preview": "extends:\n  - ../.eslintrc.yml\n\nenv:\n  mocha: true\n\nrules:\n  no-console: 2\n  no-process-exit: 0\n"
  },
  {
    "path": "test/fixtures/fixture_processor.js",
    "chars": 194,
    "preview": "/**\n * A processor file to be used in tests.\n *\n */\n'use strict';\n\nconst delay = require('delay');\n\nmodule.exports = fun"
  },
  {
    "path": "test/fixtures/fixture_processor_bar.js",
    "chars": 197,
    "preview": "/**\n * A processor file to be used in tests.\n *\n */\n'use strict';\n\nconst delay = require('delay');\n\nmodule.exports = fun"
  },
  {
    "path": "test/fixtures/fixture_processor_broken.js",
    "chars": 56,
    "preview": "'use strict';\nthrow new Error('Broken file processor');\n"
  },
  {
    "path": "test/fixtures/fixture_processor_callback.js",
    "chars": 194,
    "preview": "/**\n * A processor file to be used in tests.\n *\n */\n'use strict';\n\nconst delay = require('delay');\n\nmodule.exports = fun"
  },
  {
    "path": "test/fixtures/fixture_processor_callback_fail.js",
    "chars": 224,
    "preview": "/**\n * A processor file to be used in tests.\n *\n */\n'use strict';\n\nconst delay = require('delay');\n\nmodule.exports = fun"
  },
  {
    "path": "test/fixtures/fixture_processor_crash.js",
    "chars": 292,
    "preview": "/**\n * A processor file to be used in tests.\n *\n */\n'use strict';\n\nmodule.exports = function(job) {\n  setTimeout(() => {"
  },
  {
    "path": "test/fixtures/fixture_processor_data.js",
    "chars": 227,
    "preview": "/**\n * A processor file to be used in tests.\n *\n */\n'use strict';\n\nconst delay = require('delay');\n\nmodule.exports = fun"
  },
  {
    "path": "test/fixtures/fixture_processor_discard.js",
    "chars": 247,
    "preview": "/**\n * A processor file to be used in tests.\n *\n */\n'use strict';\n\nconst delay = require('delay');\n\nmodule.exports = fun"
  },
  {
    "path": "test/fixtures/fixture_processor_exit.js",
    "chars": 238,
    "preview": "/**\n * A processor file to be used in tests.\n *\n */\n'use strict';\n\nconst delay = require('delay');\n\nmodule.exports = fun"
  },
  {
    "path": "test/fixtures/fixture_processor_fail.js",
    "chars": 229,
    "preview": "/**\n * A processor file to be used in tests.\n *\n */\n'use strict';\n\nconst delay = require('delay');\n\nmodule.exports = fun"
  },
  {
    "path": "test/fixtures/fixture_processor_foo.js",
    "chars": 197,
    "preview": "/**\n * A processor file to be used in tests.\n *\n */\n'use strict';\n\nconst delay = require('delay');\n\nmodule.exports = fun"
  },
  {
    "path": "test/fixtures/fixture_processor_progress.js",
    "chars": 594,
    "preview": "/**\n * A processor file to be used in tests.\n *\n */\n'use strict';\n\nconst delay = require('delay');\n\nmodule.exports = fun"
  },
  {
    "path": "test/fixtures/fixture_processor_slow.js",
    "chars": 195,
    "preview": "/**\n * A processor file to be used in tests.\n *\n */\n'use strict';\n\nconst delay = require('delay');\n\nmodule.exports = fun"
  },
  {
    "path": "test/test_child-pool.js",
    "chars": 4222,
    "preview": "'use strict';\n\nconst expect = require('chai').expect;\nconst childPool = require('../lib/process/child-pool');\n\ndescribe("
  },
  {
    "path": "test/test_connection.js",
    "chars": 5228,
    "preview": "'use strict';\n\nconst expect = require('expect.js');\nconst utils = require('./utils');\nconst { isRedisReady } = require('"
  },
  {
    "path": "test/test_events.js",
    "chars": 6729,
    "preview": "'use strict';\n\nconst utils = require('./utils');\nconst redis = require('ioredis');\nconst delay = require('delay');\nconst"
  },
  {
    "path": "test/test_getters.js",
    "chars": 10484,
    "preview": "'use strict';\n\nconst redis = require('ioredis');\n\nconst utils = require('./utils');\nconst expect = require('chai').expec"
  },
  {
    "path": "test/test_job.js",
    "chars": 33778,
    "preview": "'use strict';\n\nconst Job = require('../lib/job');\nconst Queue = require('../lib/queue');\nconst expect = require('expect."
  },
  {
    "path": "test/test_metrics.js",
    "chars": 7832,
    "preview": "'use strict';\n\nconst expect = require('chai').expect;\nconst utils = require('./utils');\nconst sinon = require('sinon');\n"
  },
  {
    "path": "test/test_obliterate.js",
    "chars": 4687,
    "preview": "'use strict';\n\nconst expect = require('chai').expect;\nconst uuid = require('uuid');\nconst utils = require('./utils');\nco"
  },
  {
    "path": "test/test_pause.js",
    "chars": 12533,
    "preview": "'use strict';\n\nconst Queue = require('../');\n\nconst expect = require('chai').expect;\nconst redis = require('ioredis');\nc"
  },
  {
    "path": "test/test_queue.js",
    "chars": 100412,
    "preview": "'use strict';\n\nconst Queue = require('../');\nconst expect = require('chai').expect;\nconst redis = require('ioredis');\nco"
  },
  {
    "path": "test/test_rate_limiter.js",
    "chars": 7347,
    "preview": "'use strict';\n\nconst expect = require('chai').expect;\nconst utils = require('./utils');\nconst redis = require('ioredis')"
  },
  {
    "path": "test/test_repeat.js",
    "chars": 21473,
    "preview": "'use strict';\n\nconst expect = require('chai').expect;\nconst utils = require('./utils');\nconst sinon = require('sinon');\n"
  },
  {
    "path": "test/test_sandboxed_process.js",
    "chars": 14890,
    "preview": "'use strict';\n\nconst expect = require('chai').expect;\nconst utils = require('./utils');\nconst redis = require('ioredis')"
  },
  {
    "path": "test/test_when_current_jobs_finished.js",
    "chars": 3390,
    "preview": "'use strict';\n\nconst expect = require('chai').expect;\nconst redis = require('ioredis');\nconst utils = require('./utils')"
  },
  {
    "path": "test/test_worker.js",
    "chars": 777,
    "preview": "'use strict';\n\nconst expect = require('chai').expect;\nconst utils = require('./utils');\nconst redis = require('ioredis')"
  },
  {
    "path": "test/utils.js",
    "chars": 1156,
    "preview": "'use strict';\n\nconst Queue = require('../');\nconst STD_QUEUE_NAME = 'test queue';\nconst _ = require('lodash');\n\nlet queu"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the OptimalBits/bull GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 108 files (573.0 KB), approximately 151.6k tokens, and a symbol index with 152 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!