{"id":25445505,"url":"https://github.com/divmgl/jackd","last_synced_at":"2026-03-05T03:00:50.948Z","repository":{"id":34242337,"uuid":"172407902","full_name":"divmgl/jackd","owner":"divmgl","description":"Simple and modern beanstalkd client for Node/Bun","archived":false,"fork":false,"pushed_at":"2025-03-06T15:33:15.000Z","size":355,"stargazers_count":34,"open_issues_count":0,"forks_count":7,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-10-12T23:52:45.377Z","etag":null,"topics":["beanstalkd","bun","nodejs","queue"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/divmgl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-02-25T00:32:14.000Z","updated_at":"2025-03-11T21:41:19.000Z","dependencies_parsed_at":"2024-06-18T22:36:04.738Z","dependency_job_id":"a3b0bfa4-b0db-4fae-bfc1-e269ef8e3a1f","html_url":"https://github.com/divmgl/jackd","commit_stats":{"total_commits":71,"total_committers":10,"mean_commits":7.1,"dds":0.6338028169014085,"last_synced_commit":"3e45357fdb4ff542d48163a8b43303eab0dd8c42"},"previous_names":["getjackd/jackd"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/divmgl/jackd","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/divmgl%2Fjackd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/divmgl%2Fjackd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/divmgl%2Fjackd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/divmgl%2Fjackd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/divmgl","download_url":"https://codeload.github.com/divmgl/jackd/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/divmgl%2Fjackd/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30107638,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-05T01:39:18.192Z","status":"online","status_checked_at":"2026-03-05T02:00:06.710Z","response_time":93,"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":["beanstalkd","bun","nodejs","queue"],"created_at":"2025-02-17T16:23:16.118Z","updated_at":"2026-03-05T03:00:50.879Z","avatar_url":"https://github.com/divmgl.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# jackd\n\n![Tests](https://github.com/divmgl/jackd/actions/workflows/test.yml/badge.svg)\n\nModern beanstalkd client for Node/Bun\n\n## Quick start\n\n```ts\nimport Jackd from \"jackd\"\n\nconst client = new Jackd()\n\n// Publishing a job\nawait client.put({ greeting: \"Hello!\" })\n\n// Consuming a job\nconst job = await client.reserve() // =\u003e { id: '1', payload: '{\"greeting\":\"Hello!\"}' }\n\n// Process the job, then delete it\nawait client.delete(job.id)\n```\n\n## Installation\n\n```bash\nnpm install jackd\nyarn add jackd\npnpm add jackd\nbun add jackd\n```\n\n## Why\n\nBeanstalkd is a simple and blazing fast work queue. It's a great tool for building background job runners, pub/sub systems, and more.\n\nJackd is a modern Node/Bun client for Beanstalkd written in TypeScript. It has:\n\n- A concise and easy to use API\n- Full type safety\n- Native `Promise` support\n- A single dependency: `yaml`\n- Protocol accuracy/completeness\n\nIf you don't have experience using Beanstalkd, it's a good idea to read [the Beanstalkd protocol](https://github.com/beanstalkd/beanstalkd/blob/master/doc/protocol.txt) before using this library.\n\n## Documentation\n\n### Putting Jobs\n\nYou can add jobs to Beanstalkd by using the `put` command, which accepts a payload and returns a job ID.\n\n```ts\nconst jobId: number = await client.put({ foo: \"bar\" })\nconsole.log(jobId) // =\u003e 1\n```\n\nJob payloads are byte arrays. Passing in a `Uint8Array` will send the payload as-is.\n\n```ts\nconst jobId = await client.put([123, 123, 123])\n```\n\nYou can also pass in a `String` or an `Object` and `jackd` will automatically convert these values into byte arrays.\n\n```ts\nconst jobId = await client.put(\"my long running job\") // TextEncoder.encode(string)\nconst jobId = await client.put({ foo: \"bar\" }) // TextEncoder.encode(JSON.stringify(object))\n```\n\nAll jobs sent to beanstalkd have a priority, a delay, and TTR (time-to-run) specification. By default, all jobs are published with `0` priority, `0` delay, and `60` TTR, which means consumers will have 60 seconds to finish the job after reservation. You can override these defaults:\n\n```ts\nawait client.put(\n  { foo: \"bar\" },\n  {\n    delay: 2, // Two second delay\n    priority: 10,\n    ttr: 600 // Ten minute delay\n  }\n)\n```\n\nJobs with lower priorities are handled first. Refer to [the protocol specs](https://github.com/beanstalkd/beanstalkd/blob/master/doc/protocol.txt#L126) for more information on job options.\n\n### Reserving Jobs\n\nYou can receive jobs by using the `reserve` command:\n\n```ts\n// Get a job with string payload\nconst { id, payload } = await client.reserve()\nconsole.log({ id, payload }) // =\u003e { id: '1', payload: 'Hello!' }\n\n// Get a job with raw Uint8Array payload\nconst { id, payload } = await client.reserveRaw()\nconsole.log({ id, payload }) // =\u003e { id: '1', payload: Uint8Array }\n```\n\nJob reservation is how beanstalkd implements work distribution. Once you've reserved a job, you can process it and then delete it:\n\n```ts\nconst { id, payload } = await client.reserve()\n// Do some long-running operation\nawait client.delete(id)\n```\n\nIf you don't handle the job within 60s (which is the default TTR), the job will be released back into the queue.\n\nIf you passed in an object when putting the job, you'll need to parse the JSON string:\n\n```js\nconst { id, payload } = await client.reserve()\nconst object = JSON.parse(payload)\n```\n\nPlease keep in mind that reservation is a _blocking_ operation. This means that your script will stop executing until a job has been reserved.\n\n### Tubes\n\nBeanstalkd queues are called tubes. Clients send to and reserve jobs from tubes.\n\nClients keep a watchlist, which determines which tubes they'll reserve jobs from. By default, all clients \"watch\" the `default` tube. You can watch a new tube by using the `watch` command.\n\n```ts\n// Watch both the \"default\" and \"awesome-tube\" tubes\nconst numberOfTubesWatched = await client.watch(\"awesome-tube\")\nconsole.log(numberOfTubesWatched) // =\u003e 2\n```\n\nYou can also ignore a tube by using the `ignore` command.\n\n```ts\n// Ignore the \"default\" tube so we'll only watch \"awesome-tube\"\nconst numberOfTubesWatched = await client.ignore(\"default\")\nconsole.log(numberOfTubesWatched) // =\u003e 1\n```\n\n\u003e Note: attempting to ignore the only tube being watched will throw an exception.\n\nWhile clients can watch more than one tube at once, they can only publish jobs to the tube they're currently \"using\". Clients by default use the `default` tube.\n\nYou can change the tube you're using with the `use` command.\n\n```ts\nconst tubeName = await client.use(\"awesome-tube\")\nconsole.log(tubeName) // =\u003e 'awesome-tube'\n\nawait client.put({ foo: \"bar\" }) // This job will be published to \"awesome-tube\" rather than \"default\"\n```\n\n### Job management\n\nThe most common operation after processing a job is deleting it:\n\n```ts\nawait client.delete(id)\n```\n\nHowever, there are other things you can do with a job. For instance, you can release it back into the queue if you can't process it right now:\n\n```ts\n// Release immediately with high priority (0) and no delay (0)\nawait client.release(id)\n\n// You can also specify the priority and the delay\nawait client.release(id, { priority: 10, delay: 10 })\n```\n\nSometimes a job can't be processed, for whatever reason. A common example of this is when a job continues to fail over and over.\n\nYou can bury the job so it can be processed again later:\n\n```ts\nawait client.bury(id)\n// ... some time later ...\nawait client.kickJob(id)\n```\n\nThe `kickJob` command is a convenience method for kicking a specific job on the currently used tube into the ready queue.\n\nYou can kick multiple buried jobs at once:\n\n```ts\nawait client.kick(10) // 10 buried jobs will be moved to a ready state\n```\n\nSometimes a job is taking too long to process, but you're making progress. You can extend the time you have to process a job by touching it:\n\n```ts\nawait client.touch(id)\n```\n\nThis lets Beanstalkd know that you're still working on the job.\n\n### Statistics\n\nBeanstalkd has a number of commands that returns statistics.\n\nFor instance, the `stats` command returns details regarding the current Beanstalkd instance:\n\n```js\nconst stats = await client.stats()\nconsole.log(stats)\n/* =\u003e\n{\n  currentJobsUrgent: 0,\n  currentJobsReady: 0,\n  currentJobsReserved: 0,\n  currentJobsDelayed: 0,\n  currentJobsBuried: 0,\n  ...\n}\n*/\n```\n\nYou can also get statistics for a specific tube:\n\n```ts\nconst stats = await client.statsTube(\"awesome-tube\")\nconsole.log(stats)\n/* =\u003e\n{\n  name: \"awesome-tube\",\n  currentJobsUrgent: 0,\n  currentJobsReady: 0,\n  currentJobsReserved: 0,\n  currentJobsDelayed: 0,\n  currentJobsBuried: 0,\n  ...\n}\n*/\n```\n\nOr statistics for a specific job:\n\n```ts\nconst stats = await client.statsJob(id)\nconsole.log(stats)\n/* =\u003e\n{\n  id: \"1\",\n  tube: \"awesome-tube\",\n  state: \"ready\",\n  ...\n}\n*/\n```\n\n### Workers\n\nYou may be looking to design a process that does nothing else but consume jobs. Here's an example implementation.\n\n```ts\n/* consumer.ts */\nimport Jackd from \"jackd\"\n\nconst client = new Jackd()\n\nvoid start()\n\nasync function start() {\n  while (true) {\n    try {\n      const { id, payload } = await client.reserve()\n      /* ... process job here ... */\n      await client.delete(id)\n    } catch (err) {\n      // Capture error somehow\n      console.error(err)\n    }\n  }\n\n  process.exit(0)\n}\n```\n\nThis process will run indefinitely, consuming jobs and processing them.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdivmgl%2Fjackd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdivmgl%2Fjackd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdivmgl%2Fjackd/lists"}