{"id":19494696,"url":"https://github.com/ceejbot/fivebeans","last_synced_at":"2025-04-05T10:10:31.301Z","repository":{"id":2392099,"uuid":"3358292","full_name":"ceejbot/fivebeans","owner":"ceejbot","description":"A beanstalkd client for node.js \u0026 a simple framework for running beanstalkd workers.","archived":false,"fork":false,"pushed_at":"2020-01-04T05:31:54.000Z","size":289,"stargazers_count":181,"open_issues_count":105,"forks_count":56,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-29T09:10:39.466Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://ceejbot.github.io/fivebeans/","language":"JavaScript","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/ceejbot.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}},"created_at":"2012-02-05T08:16:22.000Z","updated_at":"2024-08-29T01:35:52.000Z","dependencies_parsed_at":"2022-07-08T22:17:02.012Z","dependency_job_id":null,"html_url":"https://github.com/ceejbot/fivebeans","commit_stats":null,"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ceejbot%2Ffivebeans","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ceejbot%2Ffivebeans/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ceejbot%2Ffivebeans/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ceejbot%2Ffivebeans/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ceejbot","download_url":"https://codeload.github.com/ceejbot/fivebeans/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247318745,"owners_count":20919484,"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","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":[],"created_at":"2024-11-10T21:32:11.214Z","updated_at":"2025-04-05T10:10:31.282Z","avatar_url":"https://github.com/ceejbot.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"A straightforward and (nearly) complete [beanstalkd](http://kr.github.com/beanstalkd/) client for node.js, along with a more opinionated beanstalkd jobs worker \u0026 runner.\n\n[![on npm](http://img.shields.io/npm/v/fivebeans.svg?style=flat)](https://www.npmjs.org/package/fivebeans)  [![Tests](http://img.shields.io/travis/ceejbot/fivebeans.svg?style=flat)](http://travis-ci.org/ceejbot/fivebeans) [![Coverage Status](https://img.shields.io/coveralls/ceejbot/fivebeans.svg?style=flat)](https://coveralls.io/github/ceejbot/fivebeans?branch=master) [![Dependencies](http://img.shields.io/david/ceejbot/fivebeans.svg?style=flat)](https://david-dm.org/ceejbot/fivebeans)\n\n## FiveBeansClient\n\nHeavily inspired by [node-beanstalk-client](https://github.com/benlund/node-beanstalk-client), which is a perfectly usable client but somewhat dusty. I wanted more complete support of the beanstalkd protocol in a project written in plain javascript.\n\nAll client method names are the same case \u0026 spelling as the beanstalk text command, with hyphens replaced by underscore. The single exception is `delete`, which is renamed to `destroy()`.\n\nFor complete details on the beanstalkd commands, see [its protocol documentation](https://github.com/kr/beanstalkd/blob/master/doc/protocol.md).\n\n### Creating a client\n\nThe client constructor takes two arguments:\n\n__host__: The address of the beanstalkd server. Defaults to `127.0.0.1`.  \n__port__: Port to connect to. Defaults to `11300`.\n\nThe client emits three events that you should listen for: `connect`, `error`, and `close`.\n\nThe client is not usable until you call its `connect()` method. Here's an example of setting up a client:\n\n```javascript\nvar fivebeans = require('fivebeans');\n\nvar client = new fivebeans.client('10.0.1.1', 11300);\nclient\n    .on('connect', function()\n    {\n        // client can now be used\n    })\n    .on('error', function(err)\n    {\n        // connection failure\n    })\n    .on('close', function()\n    {\n        // underlying connection has closed\n    })\n    .connect();\n```\n\n### Producing jobs\n\n#### use\n\n`client.use(tube, function(err, tubename) {});`\n\nUse the specified tube. Reponds with the name of the tube being used.\n\n#### list_tube_used\n\n`client.list_tube_used(function(err, tubename) {});`\n\nResponds with the name of the tube currently being used by the client.\n\n#### put\n\n`client.put(priority, delay, ttr, payload, function(err, jobid) {});`\n\nSubmit a job with the specified priority (smaller integers are higher priority), delay in seconds, and allowed time-to-run in seconds. The payload contains the job data the server will return to clients reserving jobs; it can be either a Buffer object or a string. No processing is done on the data. Responds with the id of the newly-created job.\n\n#### peek_ready\n\n`client.peek_ready(function(err, jobid, payload) {});`\n\nPeek at the data for the job at the top of the ready queue of the tube currently in use. Responds with the job id and payload of the next job, or 'NOT_FOUND' if there are no qualifying jobs in the tube. The payload is a Buffer object.\n\n#### peek_delayed\n\n`client.peek_delayed(function(err, jobid, payload) {});`\n\nPeek at the data for the delayed job with the shortest delay in the tube currently in use. Responds with the job id and payload of the next job, or 'NOT_FOUND' in *err* if there are no qualifying jobs in the tube. The payload is a Buffer object.\n\n#### peek_buried\n\n`client.peek_buried(function(err, jobid, payload) {});`\n\nPeek at the data for the next buried job in the tube currently in use. Responds with the job id and payload of the next job, or 'NOT_FOUND' in *err* if there are no qualifying jobs in the tube. The payload is a Buffer object.\n\n### Consuming jobs\n\n#### watch\n\n`client.watch(tube, function(err, numwatched) {});`\n\nWatch the named tube. Responds with the number of tubes currently watched by the client.\n\n#### ignore\n\n`client.ignore(tube, function(err, numwatched) {});`\n\nIgnore the named tube. Responds with the number of tubes currently watched by the client.\n\n#### list_tubes_watched\n\n`client.list_tubes_watched(function(err, tubelist) {});`\n\nResponds with an array containing the names of the tubes currently watched by the client.\n\n#### reserve\n\n`client.reserve(function(err, jobid, payload) {});`\n\nReserve a job. Responds with the id and the job data. The payload is a Buffer object.\n\n#### reserve_with_timeout\n\n`client.reserve_with_timeout(seconds, function(err, jobid, payload) {});`\n\nReserve a job, waiting the specified number of seconds before timing out. *err* contains the string \"TIMED_OUT\" if the specified time elapsed before a job became available. Payload is a buffer.\n\n#### touch\n\n`client.touch(jobid, function(err) {});`\n\nInform the server that the client is still processing a job, thus requesting more time to work on it.\n\n#### destroy\n\n`client.destroy(jobid, function(err) {});`\n\nDelete the specified job. Responds with null if successful, a string error otherwise. This is the only method not named identically to its beanstalkd counterpart, because delete is a reserved word in Javascript.\n\n#### release\n\n`client.release(jobid, priority, delay, function(err) {});`\n\nRelease the specified job and assign it the given priority and delay (in seconds). Responds with null if successful, a string error otherwise.\n\n#### bury\n\n`client.bury(jobid, priority, function(err) {});`\n\nBury the specified job and assign it the given priority. Responds with null if successful, a string error otherwise.\n\n#### kick\n\n`client.kick(maxToKick, function(err, numkicked) {});`\n\nKick at most *maxToKick* delayed and buried jobs back into the active queue. Responds with the number of jobs kicked.\n\n#### kick_job\n\n`client.kick_job(jobID, function(err) {});`\n\nKick the specified job id. Responds with `NOT_FOUND` if the job was not found. Supported in beanstalkd versions \u003e= 1.6.\n\n### Server statistics\n\n#### peek\n\n`client.peek(id, function(err, jobid, payload) {});`\n\nPeek at the data for the specified job. Payload is a Buffer object.\n\n#### pause_tube\n\n`client.pause_tube(tubename, delay, function(err) {});`\n\nPause the named tube for the given number of seconds. No new jobs may be reserved from the tube while it is paused.\n\n#### list_tubes\n\n`client.list_tubes(function(err, tubenames) {});`\n\nList all the existing tubes. Responds with an array of tube names.\n\n#### stats_job\n\n`client.stats_job(jobid, function(err, response) {});`\n\nRequest statistics for the specified job. Responds with a hash containing information about the job. See the beanstalkd documentation for a complete list of stats.\n\n#### stats_tube\n\n`client.stats_tube(tubename, function(err, response) {});`\n\nRequest statistics for the specified tube. Responds with a hash containing information about the tube. See the beanstalkd documentation for a complete list of stats.\n\n#### stats\n\n`client.stats(function(err, response) {});`\n\nRequest statistics for the beanstalkd server. Responds with a hash containing information about the server. See the beanstalkd documentation for a complete list of stats.\n\n## FiveBeansWorker\n\nInspired by [node-beanstalk-worker](https://github.com/benlund/node-beanstalk-worker) but updated \u0026 rewritten to work with jobs queued by [Stalker](https://github.com/kr/stalker).\n\nThe worker pulls jobs off the queue \u0026 passes them to matching handlers. It deletes successful jobs \u0026 buries unsuccessful ones. It continues processing past all recoverable errors, though it emits events on error.\n\n### API\n\n#### constructor\n\n`new FiveBeansWorker(options)`\n\nReturns a new worker object. *options* is a hash containing the following keys:\n\n__id__: how this worker should identify itself in log events  \n__host__: beanstalkd host  \n__port__: beanstalkd port  \n__handlers__: hash with handler objects, with handler types as keys  \n__ignoreDefault__: true if this worker should ignore the default tube\n__timeout__: timeout parameter used with on reserve_with_timeout, defaults to 10 (in seconds)\n\n#### start\n\n`start(tubelist)`\n\nConnect the worker to the beanstalkd server \u0026 make it watch the specified tubes. Emits the 'started' event when it is complete.\n\n#### stop\n\n`stop()`\n\nFinish processing the current job then close the client. Emits the 'stopped' event when complete.\n\n#### watch\n\n`watch(tubelist, callback)`\n\nBegin watching the tubes named in the list.\n\n#### ignore\n\n`ignore(tubelist, callback)`\n\nIgnore the tubes named in the list.\n\n\n### Events\n\nThe worker is intended to continue processing jobs through most errors. Its response to exceptions encountered when processing jobs is to bury the job and emit an event that can be logged or handled somewhere else.\n\n`error`: Emitted on error in the underlying client. Payload is the error object. Execution is halted. You must listen for this event.\n\n`close`: Emitted on close in the underlying client. No payload.\n\n`started`: Worker has started processing. No payload.\n\n`stopped`: Worker has stopped processing. No payload.\n\n`info`: The worker has taken some action that you might want to log. The payload is an object with information about the action, with two fields:\n\n```javascript\n{\n    clientid: 'id-of-worker',\n    message: 'a logging-style description of the action'\n}\n```\n\nThis event is the tattered remnants of what used to be built-in logging, and it might go away.\n\n`warning`: The worker has encountered an error condition that will not stop processing, but that you might wish to act upon or log. The payload is an object with information about the error. Fields guaranteed to be present are:\n\n```javascript\n{\n    clientid: 'id-of-worker',\n    message: 'the context of the error',\n    error: errorObject\n}\n```\n\nSome errors might have additional fields providing context, such as a job id.\n\n`job.reserved`: The worker has reserved a job. The payload is the job id.\n\n`job.handled`: The worker has completed processing a job. The payload is an object with information about the job.\n\n```javascript\n{\n    id: job id,\n    type: job type,\n    elapsed: elapsed time in ms,\n    action: [ 'success' | 'release' | 'bury' | custom error message ]\n}\n```\n\n`job.deleted`: The worker has deleted a job. The payload is the job id.\n\n`job.buried`: The worker has buried a job. The payload is the job id.\n\n### Jobs\n\nEach job must be a JSON-serialized object with two fields:\n\n__type__: type string matching a handler  \n__payload__: job data, in whatever format the job defines\n\nThe worker looks up a handler using the given type string and calls work() on the job payload.\n\nThe job *may* also be a JSON array containing two items:\n\n`[ tubename, jobdata ]`\n\nWhere the second item is an object as specified above. This is for compatibility with the Stalker library, which wraps the job data this way.\n\n### Handlers\n\nHandler modules must export a single function that returns an object. The object must have a field called 'type' with a brief descriptive string. It must also expose a function called work() with this signature:\n\n`work(jobdata, callback(action, delay))`\n\n__jobdata__: job payload  \n__action__: 'success' | 'release' | 'bury' | custom error message  \n__delay__: seconds to delay if the job is released; otherwise unused\n\nIf the *action* is \"success\", the job is deleted. If it is \"release\", the job is released with the specified delay. If it is \"bury\", the job is buried. All other actions are treated as errors \u0026 the job is buried in response.\n\nHere's a simple handler example.\n\n```javascript\nmodule.exports = function()\n{\n    function EmitKeysHandler()\n    {\n        this.type = 'emitkeys';\n    }\n\n    EmitKeysHandler.prototype.work = function(payload, callback)\n    {\n        var keys = Object.keys(payload);\n        for (var i = 0; i \u003c keys.length; i++)\n            console.log(keys[i]);\n        callback('success');\n    }\n\n    var handler = new EmitKeysHandler();\n    return handler;\n};\n```\n\nThe [examples](examples) directory has another sample handler.\n\n### Example\n\nThis example starts a worker capable of handling the `emitkeys` example from above.\n\n```javascript\nvar Beanworker = require('fivebeans').worker;\nvar options =\n{\n    id: 'worker_4',\n    host: '127.0.0.1',\n    port: 11300,\n    handlers:\n    {\n        emitkeys: require('./emitkeyshandler')()\n    },\n    ignoreDefault: true\n}\nvar worker = new Beanworker(options);\nworker.start(['high', 'medium', 'low']);\n```\n\n## FiveBeansRunner\n\nA wrapper that runs a single beanstalkd worker as a daemon. Responds to the USR2 signal by reloading the configuration and restarting the worker. Handles SIGINT, SIGHUP, and SIGQUIT by completing processing on the current job then stopping.\n\nExample use:\n\n```javascript\nvar fivebeans = require('fivebeans');\nvar runner = new fivebeans.runner('worker_id_1', '/path/to/config.yml');\nrunner.go();\n```\n\n### bin/beanworker\n\nThe above code plus [yargs](https://github.com/chevex/yargs) wrapped in a node shell script for your convenience.\n\n`bin/beanworker --id=[ID] --config=[config.yml]`\n\nCreates a runner for a worker with the specified ID \u0026 configured with the specified yaml file.\n\nHere's the complete source:\n\n```javascript\n#!/usr/bin/env node\n\nvar argv = require('yargs')\n    .usage('Usage: beanworker --id=[ID] --config=[config.yml]')\n    .default('id', 'defaultID')\n    .demand(['config'])\n    .argv;\n\nvar FiveBeans = require('fivebeans');\n\nvar runner = new FiveBeans.runner(argv.id, argv.config);\nrunner.go();\n```\n\n### Configuration file\n\nHere's an example yaml configuration:\n\n```yaml\nbeanstalkd:\n    host: \"127.0.0.1\"\n    port: 11300\nwatch:\n    - 'circle'\n    - 'picadilly'\n    - 'northern'\n    - 'central'\nhandlers:\n    - \"./handlers/holborn.js\"\n    - \"./handlers/greenpark.js\"\n    - \"./handlers/knightsbridge.js\"\nignoreDefault: true\n```\n\n__beanstalkd__: where to connect  \n__watch__: a list of tubes to watch.  \n__handlers__: a list of handler files to require  \n__ignoreDefault__: true if this worker should ignore the default tube\n\nIf the handler paths don't start with `/` the current working directory will be prepended to them before they are required.\n\nWhy yaml not json? Because when I originally wrote this, it was in support of a ruby service, and yaml is the native config format over in that land. I continue using it because it's more readable than json and easier for humans to type.\n\n## Contributors\n\n@AVVS  \n@crackcomm  \n@zr40  \nJon Keating\nJevgenij Tsoi\n\nMany thanks!\n\n## TODO\n\n* Handle DEADLINE_SOON from the server.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fceejbot%2Ffivebeans","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fceejbot%2Ffivebeans","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fceejbot%2Ffivebeans/lists"}