{"id":16095852,"url":"https://github.com/joakin/task-queue","last_synced_at":"2025-10-10T18:54:30.689Z","repository":{"id":57121576,"uuid":"161784043","full_name":"joakin/task-queue","owner":"joakin","description":"A customizable job/task queue for javascript processes.","archived":false,"fork":false,"pushed_at":"2018-12-15T21:06:47.000Z","size":36,"stargazers_count":5,"open_issues_count":3,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-08-04T20:36:46.954Z","etag":null,"topics":["concurrency","nodejs","queue","task","task-queue","typescript"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/joakin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-12-14T12:51:21.000Z","updated_at":"2022-02-06T16:32:23.000Z","dependencies_parsed_at":"2022-08-24T06:31:07.785Z","dependency_job_id":null,"html_url":"https://github.com/joakin/task-queue","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/joakin/task-queue","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joakin%2Ftask-queue","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joakin%2Ftask-queue/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joakin%2Ftask-queue/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joakin%2Ftask-queue/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/joakin","download_url":"https://codeload.github.com/joakin/task-queue/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joakin%2Ftask-queue/sbom","scorecard":{"id":525571,"data":{"date":"2025-08-11","repo":{"name":"github.com/joakin/task-queue","commit":"0e9a22cd8f32d2a12b110152811d5014868177a0"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/14 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":5,"reason":"5 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-20T04:15:31.908Z","repository_id":57121576,"created_at":"2025-08-20T04:15:31.908Z","updated_at":"2025-08-20T04:15:31.908Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279004906,"owners_count":26083802,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-10T02:00:06.843Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["concurrency","nodejs","queue","task","task-queue","typescript"],"created_at":"2024-10-09T17:09:14.447Z","updated_at":"2025-10-10T18:54:30.673Z","avatar_url":"https://github.com/joakin.png","language":"TypeScript","readme":"# task-queue\n\n`npm install @joakin/task-queue`\n\nA customizable job/task queue for javascript processes.\n\n```js\nimport { Queue } from \"@joakin/task-queue\";\n\nconst queue = Queue();\n\nqueue.add(hardToDoComputation).then(result =\u003e console.log(result));\n```\n\n- Promise based\n- Queued jobs can be cancelled\n- Configurable:\n  - `queueTimeout`: Time a job spends waiting in the queue\n  - `executionTimeout`: Time a job can spend executing\n  - `concurrency`: How many jobs should be run concurrently\n  - `maxTaskCount`: How many tasks can the queue hold\n- All activity is reported via events on the queue for easy logging/monitoring\n- Typescript definitions\n\n## Usage\n\n### Creating a queue\n\nQueues are created by default with the following arguments:\n\n```ts\nconst defaultQueue = Queue({\n  queueTimeout: 500,\n  executionTimeout: 250,\n  concurrency: 1,\n  maxTaskCount: 1\n});\n```\n\nFeel free to pass in only the ones you want to modify when creating one.\n\n### Enqueueing jobs\n\nFor adding a job to the queue, just call `queue.add(fn)`, where `fn` is a\nfunction that returns a promise.\n\nThe queue will save the closure and run it when it is its turn. When calling\n`add`, you get back a `Promise` with a `cancel` method that you can call to\nremove the job from the queue.\n\n```ts\nqueue.add(() =\u003e printToPdf(url)).then(pdf =\u003e res.send(pdf));\n```\n\n### Removing jobs from the queue\n\nWhen you add a job, you will get back a promise with a `cancel` method that you\ncan call to remove the job from the queue, whatever its state is (waiting or\nrunning).\n\n```ts\n// Timeout example for illustration purposes. You can do timeouts better with the queue parameters though.\n\nconst job = queue.add(() =\u003e printToPdf(url));\nconst timeout = setTimeout(() =\u003e job.cancel(), 10000);\njob.then(pdf =\u003e {\n  clearTimeout(timeout);\n  res.send(pdf);\n});\n```\n\nYou can also specify a callback for when the job is cancelled, by calling\n`queue.add(job, onCancel)`. In onCancel you can do cleanup work in case your job\nhas started running:\n\n```ts\nlet browser;\nconst job = queue\n  .add(\n    () =\u003e {\n      browser = launchBrowser();\n      printToPdf(browser, url);\n    },\n    () =\u003e {\n      if (browser) closeBrowser(browser);\n    }\n  )\n  .then(pdf =\u003e {\n    res.send(pdf);\n  });\n```\n\n### Queue status\n\nYou can get the status of the queue by calling `queue.stats()`:\n\n```ts\nconsole.log(queue.stats());\n/*\n  {\n    jobs: {\n      total: 10,\n      inProgress: 4,\n      waiting: 6\n    },\n    full: true\n  }\n*/\n```\n\n### Handling errors\n\nThere are different error cases for an enqueued job. The promise returned when\nenqueueing a job can reject with different types of errors, if you want fine\ngrained control over the reason why it failed.\n\nFor logging/metrics purposes, see next section about events.\n\n```ts\nqueue.add(job).catch(err =\u003e {\n  if (err instanceof QueueTimeout) {\n    // Item timed out in the queue (queueTimeout configuration option)\n  } else if (err instanceof QueueFull) {\n    // The queue is full\n  } else if (err instanceof JobCancelled) {\n    // A job was cancelled\n  } else if (err instanceof JobTimeout) {\n    // A job timed out when running (executionTimeout configuration option)\n  } else {\n    // Something else failed when running the job function\n  }\n});\n```\n\n### Monitoring and logging queue activity\n\nThe queue instance is also an event emitter, and will emit events for the\nactivity on the queue that you can listen to.\n\nEvents related to queue are under the `queue.*` topic, and events related to\njobs are under the `job.*` topic.\n\n#### Queue events\n\n```ts\n// New item added to the queue\nqueue.on(\"queue.new\", ({ id, inProgressCount, waitingCount }) =\u003e {});\n\n// Item timed out in the queue (queueTimeout configuration option)\nqueue.on(\"queue.timeout\", ({ id, addedToTheQueueAt }) =\u003e {});\n\n// The queue is full\nqueue.on(\"queue.full\", ({ waitingCount, inProgressCount }) =\u003e {});\n```\n\n#### Job events\n\n```ts\n// A job started running\nqueue.on(\"job.started\", ({ id, addedToTheQueueAt }) =\u003e {});\n\n// A job successfully finished\nqueue.on(\"job.success\", ({ id, addedToTheQueueAt, startedProcessingAt }) =\u003e {});\n\n// A job timed out when running (executionTimeout configuration option)\nqueue.on(\"job.timeout\", ({ id, addedToTheQueueAt, startedProcessingAt }) =\u003e {});\n\n// A job was cancelled\nqueue.on(`job.cancel`, ({ id, addedToTheQueueAt }) =\u003e {});\n\n// A job failed when run (promise rejected or running the function threw)\nqueue.on(\n  \"job.failure\",\n  ({ id, addedToTheQueueAt, startedProcessingAt, err }) =\u003e {}\n);\n```\n\n## Types\n\nHere's the type (typescript format) definitions if you want to get a better\nunderstanding of what types the library provides and expects:\n\n```ts\nimport { EventEmitter } from \"events\";\n\nexport { Queue, JobCancelled, QueueTimeout, QueueFull, JobTimeout };\n\ndeclare function Queue({\n  queueTimeout,\n  executionTimeout,\n  concurrency,\n  maxTaskCount\n}?: {\n  queueTimeout?: number | undefined;\n  executionTimeout?: number | undefined;\n  concurrency?: number | undefined;\n  maxTaskCount?: number | undefined;\n}): QueueInstance;\n\ninterface QueueInstance extends EventEmitter {\n  add: \u003cT\u003e(\n    fn: () =\u003e Promise\u003cT\u003e,\n    onCancel?: () =\u003e void\n  ) =\u003e CancellablePromise\u003cT\u003e;\n  stats(): QueueStats;\n}\n\ninterface CancellablePromise\u003cT\u003e extends Promise\u003cT\u003e {\n  cancel: () =\u003e void;\n}\n\ninterface QueueStats {\n  jobs: {\n    total: number;\n    inProgress: number;\n    waiting: number;\n  };\n  full: boolean;\n}\n\n/**\n * Error thrown when job gets cancelled. The promise returned by the\n * queue gets rejected with JobCancelled\n */\ndeclare class JobCancelled extends Error {\n  constructor();\n}\n/**\n * Thrown when task timeouts in the queue\n */\ndeclare class QueueTimeout extends Error {\n  addedToTheQueueAt: number;\n  constructor(addedToTheQueueAt: number);\n}\n/**\n * Thrown when there is no space for new task\n */\ndeclare class QueueFull extends Error {\n  waitingCount: number;\n  inProgressCount: number;\n  constructor(waitingCount: number, inProgressCount: number);\n}\n/**\n * Thrown when task processing takes too much time\n */\ndeclare class JobTimeout extends Error {\n  constructor();\n}\n```\n\n## Rationale\n\nThis library is extracted from\n[wikimedia/mediawiki-services-chromium-render/lib/queue.js](https://github.com/wikimedia/mediawiki-services-chromium-render/blob/6ba6069eb46e803f9249226dbca0222c34b3cac3/lib/queue.js),\nwhere we needed an in-process queue for production pdf rendering services.\n\nInitially, `async.js/queue` was used, but wanting to use promises, configuring\ntimeouts and cancelling jobs made the Reading Web team at the Wikimedia\nFoundation build their own task queue implementation for their production use\ncase.\n\nThis library is an adaptation of that work, with the following initial changes\nto it:\n\n- Good documentation, types, and public API\n- Functional API instead of OO class API\n- Renamed events and errors for consistency of the public API\n- Migrated the project to strict typescript, for easier maintainability,\n  documentation, and correctness\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoakin%2Ftask-queue","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoakin%2Ftask-queue","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoakin%2Ftask-queue/lists"}