{"id":13462959,"url":"https://github.com/nesquena/backburner","last_synced_at":"2025-05-14T06:12:36.699Z","repository":{"id":4061470,"uuid":"5165118","full_name":"nesquena/backburner","owner":"nesquena","description":"Simple and reliable beanstalkd job queue for ruby","archived":false,"fork":false,"pushed_at":"2024-11-11T16:39:26.000Z","size":515,"stargazers_count":433,"open_issues_count":48,"forks_count":70,"subscribers_count":22,"default_branch":"master","last_synced_at":"2025-05-13T19:06:22.143Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://nesquena.github.com/backburner","language":"Ruby","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/nesquena.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","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":"2012-07-24T12:14:12.000Z","updated_at":"2025-04-13T08:53:13.000Z","dependencies_parsed_at":"2024-10-30T15:00:31.436Z","dependency_job_id":"058226ac-d2a1-4b6d-b6e7-bb74cb14d62f","html_url":"https://github.com/nesquena/backburner","commit_stats":{"total_commits":311,"total_committers":33,"mean_commits":9.424242424242424,"dds":"0.30546623794212213","last_synced_commit":"476a5abe9523dfed8473223ac91373127f45a732"},"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nesquena%2Fbackburner","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nesquena%2Fbackburner/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nesquena%2Fbackburner/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nesquena%2Fbackburner/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nesquena","download_url":"https://codeload.github.com/nesquena/backburner/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254080573,"owners_count":22011445,"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-07-31T13:00:42.392Z","updated_at":"2025-05-14T06:12:36.624Z","avatar_url":"https://github.com/nesquena.png","language":"Ruby","funding_links":[],"categories":["Background Processing","Ruby","Gems","Queues and Messaging"],"sub_categories":["Background Jobs"],"readme":"# Backburner [![Build Status](https://travis-ci.org/nesquena/backburner.svg?branch=master)](https://travis-ci.org/nesquena/backburner)\n\nBackburner is a [beanstalkd](https://beanstalkd.github.io/)-powered job queue that can handle a very high volume of jobs.\nYou create background jobs and place them on multiple work queues to be processed later.\n\nProcessing background jobs reliably has never been easier than with beanstalkd and Backburner. This gem works with any ruby-based\nweb framework, but is especially suited for use with [Sinatra](http://sinatrarb.com), [Padrino](http://padrinorb.com) and Rails.\n\nIf you want to use beanstalk for your job processing, consider using Backburner.\nBackburner is heavily inspired by Resque and DelayedJob. Backburner stores all jobs as simple JSON message payloads.\nPersistent queues are supported when beanstalkd persistence mode is enabled.\n\nBackburner supports multiple queues, job priorities, delays, and timeouts. In addition,\nBackburner has robust support for retrying failed jobs, handling error cases,\ncustom logging, and extensible plugin hooks.\n\n## Why Backburner?\n\nBackburner is well tested and has a familiar, no-nonsense approach to job processing, but that is of secondary importance.\nLet's face it, there are a lot of options for background job processing. [DelayedJob](https://github.com/collectiveidea/delayed_job),\nand [Resque](https://github.com/resque/resque) are the first that come to mind immediately. So, how do we make sense\nof which one to use? And why use Backburner over other alternatives?\n\nThe key to understanding the differences lies in understanding the different projects and protocols that power these popular queue\nlibraries under the hood. Every job queue requires a queue store that jobs are put into and pulled out of.\nIn the case of Resque, jobs are processed through **Redis**, a persistent key-value store. In the case of DelayedJob, jobs are processed through\n**ActiveRecord** and a database such as PostgreSQL.\n\nThe work queue underlying these gems tells you infinitely more about the differences than anything else.\nBeanstalk is probably the best solution for job queues available today for many reasons.\nThe real question then is... \"Why Beanstalk?\".\n\n## Why Beanstalk?\n\nIllya has an excellent blog post\n[Scalable Work Queues with Beanstalk](http://www.igvita.com/2010/05/20/scalable-work-queues-with-beanstalk/) and\nAdam Wiggins posted [an excellent comparison](http://adam.herokuapp.com/past/2010/4/24/beanstalk_a_simple_and_fast_queueing_backend/).\n\nYou will quickly see that **beanstalkd** is an underrated but incredible project that is extremely well-suited as a job queue.\nSignificantly better suited for this task than Redis or a database. Beanstalk is a simple,\nand a very fast work queue service rolled into a single binary - it is the memcached of work queues.\nOriginally built to power the backend for the 'Causes' Facebook app, it is a mature and production ready open source project.\n[PostRank](http://www.postrank.com) uses beanstalk to reliably process millions of jobs a day.\n\nA single instance of Beanstalk is perfectly capable of handling thousands of jobs a second (or more, depending on your job size)\nbecause it is an in-memory, event-driven system. Powered by libevent under the hood,\nit requires zero setup (launch and forget, à la memcached), optional log based persistence, an easily parsed ASCII protocol,\nand a rich set of tools for job management that go well beyond a simple FIFO work queue.\n\nBeanstalkd supports the following features out of the box:\n\n| Feature | Description                     |\n| ------- | ------------------------------- |\n| **Parallelized**    | Supports multiple work queues created on demand. |\n| **Reliable**        | Beanstalk’s reserve, work, delete cycle ensures reliable processing. |\n| **Scheduling**      | Delay enqueuing jobs by a specified interval to schedule processing later |\n| **Fast**            | Processes thousands of jobs per second without breaking a sweat. |\n| **Priorities**      | Specify priority so important jobs can be processed quickly. |\n| **Persistence**     | Jobs are stored in memory for speed, but logged to disk for safe keeping. |\n| **Federation**      | Horizontal scalability provided through federation by the client. |\n| **Error Handling**  | Bury any job which causes an error for later debugging and inspection.|\n\nKeep in mind that these features are supported out of the box with beanstalk and require no special code within this gem to support.\nIn the end, **beanstalk is the ideal job queue** while also being ridiculously easy to install and setup.\n\n## Installation\n\nFirst, you probably want to [install beanstalkd](https://beanstalkd.github.io/download.html), which powers the job queues.\nDepending on your platform, this should be as simple as (for Ubuntu):\n\n    $ sudo apt-get install beanstalkd\n\nAdd this line to your application's Gemfile:\n\n    gem 'backburner'\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install backburner\n\n## Configuration ##\n\nBackburner is extremely simple to setup. Just configure basic settings for backburner:\n\n```ruby\nBackburner.configure do |config|\n  config.beanstalk_url       = \"beanstalk://127.0.0.1\"\n  config.tube_namespace      = \"some.app.production\"\n  config.namespace_separator = \".\"\n  config.on_error            = lambda { |e| puts e }\n  config.max_job_retries     = 3 # default 0 retries\n  config.retry_delay         = 2 # default 5 seconds\n  config.retry_delay_proc    = lambda { |min_retry_delay, num_retries| min_retry_delay + (num_retries ** 3) }\n  config.default_priority    = 65536\n  config.respond_timeout     = 120\n  config.default_worker      = Backburner::Workers::Simple\n  config.logger              = Logger.new(STDOUT)\n  config.primary_queue       = \"backburner-jobs\"\n  config.priority_labels     = { :custom =\u003e 50, :useless =\u003e 1000 }\n  config.reserve_timeout     = nil\n  config.job_serializer_proc = lambda { |body| JSON.dump(body) }\n  config.job_parser_proc     = lambda { |body| JSON.parse(body) }\n\nend\n```\n\nThe key options available are:\n\n| Option                | Description                                                          |\n| -----------------     | -------------------------------                                      |\n| `beanstalk_url`       | Address for beanstalkd connection i.e 'beanstalk://127.0.0.1'        |\n| `tube_namespace`      | Prefix used for all tubes related to this backburner queue.          |\n| `namespace_separator` | Separator used for namespace and queue name                          |\n| `on_error`            | Lambda invoked with the error whenever any job in the system fails.  |\n| `max_job_retries`     | Integer defines how many times to retry a job before burying.        |\n| `retry_delay`         | Integer defines the base time to wait (in secs) between job retries. |\n| `retry_delay_proc`    | Lambda calculates the delay used, allowing for exponential back-off. |\n| `default_priority`    | Integer The default priority of jobs                                 |\n| `respond_timeout`     | Integer defines how long a job has to complete its task              |\n| `default_worker`      | Worker class that will be used if no other worker is specified.      |\n| `logger`              | Logger recorded to when backburner wants to report info or errors.   |\n| `primary_queue`       | Primary queue used for a job when an alternate queue is not given.   |\n| `priority_labels`     | Hash of named priority definitions for your app.                     |\n| `reserve_timeout`     | Duration to wait for work from a single server, or nil for forever.  |\n| `job_serializer_proc` | Lambda serializes a job body to a string to write to the task        |\n| `job_parser_proc`     | Lambda parses a task body string to a hash                           |\n\n## Breaking Changes\n\nBefore **v0.4.0**: Jobs were placed into default queues based on the name of the class creating the queue. i.e NewsletterJob would\nbe put into a 'newsletter-job' queue. As of 0.4.0, all jobs are placed into a primary queue named \"my.app.namespace.backburner-jobs\"\nunless otherwise specified.\n\n## Usage\n\nBackburner allows you to create jobs and place them onto any number of beanstalk tubes, and later pull those jobs off the tubes and\nprocess them asynchronously with a worker.\n\n### Enqueuing Jobs ###\n\nAt the core, Backburner is about jobs that can be processed asynchronously. Jobs are simple ruby objects which respond to `perform`.\n\nJob objects are queued as JSON onto a tube to be later processed by a worker. Here's an example:\n\n```ruby\nclass NewsletterJob\n  # required\n  def self.perform(email, body)\n    NewsletterMailer.deliver_text_to_email(email, body)\n  end\n\n  # optional, defaults to 'backburner-jobs' tube\n  def self.queue\n    \"newsletter-sender\"\n  end\n\n  # optional, defaults to default_priority\n  def self.queue_priority\n    1000 # most urgent priority is 0\n  end\n\n  # optional, defaults to respond_timeout in config\n  def self.queue_respond_timeout\n    300 # number of seconds before job times out, 0 to avoid timeout. NB: A timeout of 1 second will likely lead to race conditions between Backburner and beanstalkd and should be avoided\n  end\n\n  # optional, defaults to retry_delay_proc in config\n  def self.queue_retry_delay_proc\n    lambda { |min_retry_delay, num_retries| min_retry_delay + (num_retries ** 5) }\n  end\n\n  # optional, defaults to retry_delay in config\n  def self.queue_retry_delay\n    5\n  end\n\n  # optional, defaults to max_job_retries in config\n  def self.queue_max_job_retries\n    5\n  end\nend\n```\n\nYou can include the optional `Backburner::Queue` module so you can easily specify queue settings for this job:\n\n```ruby\nclass NewsletterJob\n  include Backburner::Queue\n  queue \"newsletter-sender\"  # defaults to 'backburner-jobs' tube\n  queue_priority 1000 # most urgent priority is 0\n  queue_respond_timeout 300 # number of seconds before job times out, 0 to avoid timeout\n\n  def self.perform(email, body)\n    NewsletterMailer.deliver_text_to_email(email, body)\n  end\nend\n```\n\nJobs can be enqueued with:\n\n```ruby\nBackburner.enqueue NewsletterJob, 'foo@admin.com', 'lorem ipsum...'\n```\n\n`Backburner.enqueue` accepts first a ruby object that supports `perform` and then a series of parameters\nto that object's `perform` method. The queue name used by default is `{namespace}.backburner-jobs`\nunless otherwise specified.\n\nYou may also pass a lambda as the queue name and it will be evaluated when enqueuing a\njob (and passed the Job's class as an argument). This is especially useful when combined\nwith \"Simple Async Jobs\" (see below).\n\n### Simple Async Jobs ###\n\nIn addition to defining custom jobs, a job can also be enqueued by invoking the `async` method on any object which\nincludes `Backburner::Performable`. Async enqueuing works for both instance and class methods on any _performable_ object.\n\n```ruby\nclass User\n  include Backburner::Performable\n  queue \"user-jobs\"  # defaults to 'user'\n  queue_priority 500 # most urgent priority is 0\n  queue_respond_timeout 300 # number of seconds before job times out, 0 to avoid timeout\n\n  def activate(device_id)\n    @device = Device.find(device_id)\n    # ...\n  end\n\n  def self.reset_password(user_id)\n    # ...\n  end\nend\n\n# Async works for instance methods on a persisted object with an `id`\n@user = User.first\n@user.async(:ttr =\u003e 100, :queue =\u003e \"activate\").activate(@device.id)\n# ..and for class methods\nUser.async(:pri =\u003e 100, :delay =\u003e 10.seconds).reset_password(@user.id)\n```\n\nThis automatically enqueues a job for that user record that will run `activate` with the specified argument.\nNote that you can set the queue name and queue priority at the class level and\nyou are also able to pass `pri`, `ttr`, `delay` and `queue` directly as options into `async`.\n\nThe queue name used by default is `{namespace}.backburner-jobs` if not otherwise\nspecified.\n\nIf a lambda is given for `queue`, then it will be called and given the\n_performable_ object's class as an argument:\n\n```ruby\n# Given the User class above\nUser.async(:queue =\u003e lambda { |user_klass| [\"queue1\",\"queue2\"].sample(1).first }).do_hard_work # would add the job to either queue1 or queue2 randomly\n```\n\n### Using Async Asynchronously ###\n\nIt's often useful to be able to configure your app in production such that every invocation of a method is asynchronous by default as seen in [delayed_job](https://github.com/collectiveidea/delayed_job#queuing-jobs). To accomplish this, the `Backburner::Performable` module exposes two `handle_asynchronously` convenience methods\nwhich accept the same options as the `async` method:\n\n```ruby\nclass User\n  include Backburner::Performable\n\n  def send_welcome_email\n    # ...\n  end\n\n  # ---\u003e For instance methods\n  handle_asynchronously :send_welcome_email, queue: 'send-mail', pri: 5000, ttr: 60\n\n  def self.update_recent_visitors\n    # ...\n  end\n\n  # ---\u003e For class methods\n  handle_static_asynchronously :update_recent_visitors, queue: 'long-tasks', ttr: 300\nend\n```\n\nNow, all calls to `User.update_recent_visitors` or `User#send_welcome_email` will automatically be handled asynchronously when invoked. Similarly, you can call these methods directly on the `Backburner::Performable` module to apply async behavior outside the class:\n\n```ruby\n# Given the User class above\nBackburner::Performable.handle_asynchronously(User, :activate, ttr: 100, queue: 'activate')\n```\n\nNow all calls to the `activate` method on a `User` instance will be async with the provided options.\n\n#### A Note About Auto-Async\n\nBecause an async proxy is injected and used in place of the original method, you must not rely on the return value of the method. Using the example `User` class above, if my `send_welcome_email` returned the status of an email submission and I relied on that to take some further action, I will be surprised after rewiring things with `handle_asynchronously` because the async proxy actually returns the (boolean) result of `Backburner::Worker.enqueue`.\n\n### Working Jobs\n\nBackburner workers are processes that run forever handling jobs that are reserved from the queue. Starting a worker in ruby code is simple:\n\n```ruby\nBackburner.work\n```\n\nThis will process jobs in all queues but you can also restrict processing to specific queues:\n\n```ruby\nBackburner.work('newsletter-sender', 'push-notifier')\n```\n\nThe Backburner worker also exists as a rake task:\n\n```ruby\nrequire 'backburner/tasks'\n```\n\nso you can run:\n\n```\n$ QUEUE=newsletter-sender,push-notifier rake backburner:work\n```\n\nYou can also run the backburner binary for a convenient worker:\n\n```\nbundle exec backburner -q newsletter-sender,push-notifier -d -P /var/run/backburner.pid -l /var/log/backburner.log\n```\n\nThis will daemonize the worker and store the pid and logs automatically. For Rails and Padrino, the environment should\nload automatically. For other cases, use the `-r` flag to specify a file to require.\n\n### Delaying Jobs\n\nIn Backburner, jobs can be delayed by specifying the `delay` option whenever you enqueue a job. If you want to schedule a job for an hour from now, simply add that option while enqueuing the standard job:\n\n```ruby\nBackburner::Worker.enqueue(NewsletterJob, ['foo@admin.com', 'lorem ipsum...'], :delay =\u003e 1.hour)\n```\n\nor while you schedule an async method call:\n\n```ruby\nUser.async(:delay =\u003e 1.hour).reset_password(@user.id)\n```\n\nBackburner will take care of the rest!\n\n### Persistence\n\nJobs are persisted to queues as JSON objects. Let's take our `User`\nexample from above. We'll run the following code to create a job:\n\n``` ruby\nUser.async.reset_password(@user.id)\n```\n\nThe following JSON will be put on the `{namespace}.backburner-jobs` queue:\n\n``` javascript\n{\n    'class': 'User',\n    'args': [nil, 'reset_password', 123]\n}\n```\n\nThe first argument is the 'id' of the object in the case of an instance method being async'ed. For example:\n\n```ruby\n@device = Device.find(987)\n@user = User.find(246)\n@user.async.activate(@device.id)\n```\n\nwould be stored as:\n\n``` javascript\n{\n    'class': 'User',\n    'args': [246, 'activate', 987]\n}\n```\n\nSince all jobs are persisted in JSON, your jobs must only accept arguments that can be encoded into that format.\nThis is why our examples use object IDs instead of passing around objects.\n\n### Named Priorities\n\nAs of v0.4.0, Backburner has support for named priorities. beanstalkd priorities are numerical but\nbackburner supports a mapping between a word and a numerical value. The following priorities are\navailable by default: `high` is 0, `medium` is 100, and `low` is 200.\n\nPriorities can be customized with:\n\n```ruby\nBackburner.configure do |config|\n  config.priority_labels = { :custom =\u003e 50, :useful =\u003e 5 }\n  # or append to default priorities with\n  # config.priority_labels  = Backburner::Configuration::PRIORITY_LABELS.merge(:foo =\u003e 5)\nend\n```\n\nand then these aliases can be used anywhere that a numerical value can:\n\n```ruby\nBackburner::Worker.enqueue NewsletterJob, [\"foo\", \"bar\"], :pri =\u003e :custom\nUser.async(:pri =\u003e :useful, :delay =\u003e 10.seconds).reset_password(@user.id)\n```\n\nUsing named priorities can greatly simplify priority management.\n\n### Processing Strategies\n\nIn Backburner, there are several different strategies for processing jobs\nwhich are reflected by multiple worker subclasses.\nCustom workers can be [defined fairly easily](https://github.com/nesquena/backburner/wiki/Defining-Workers).\nBy default, Backburner comes with the following workers built-in:\n\n| Worker | Description                                                                 |\n| ------- | -------------------------------                                            |\n| `Backburner::Workers::Simple` | Single threaded, no forking worker. Simplest option. |\n| `Backburner::Workers::Forking` | Basic forking worker that manages crashes and memory bloat. |\n| `Backburner::Workers::ThreadsOnFork` | Forking worker that utilizes threads for concurrent processing. |\n| `Backburner::Workers::Threading` | Utilizes thread pools for concurrent processing. |\n\nYou can select the default worker for processing with:\n\n```ruby\nBackburner.configure do |config|\n  config.default_worker = Backburner::Workers::Forking\nend\n```\n\nor determine the worker on the fly when invoking `work`:\n\n```ruby\nBackburner.work('newsletter-sender', :worker =\u003e Backburner::Workers::ThreadsOnFork)\n```\n\nor through associated rake tasks with:\n\n```\n$ QUEUE=newsletter-sender,push-message THREADS=2 GARBAGE=1000 rake backburner:threads_on_fork:work\n```\n\nWhen running on MRI or another Ruby implementation with a Global Interpreter Lock (GIL), do not be surprised if you're unable to saturate multiple cores, even with the threads_on_fork worker. To utilize multiple cores, you must run multiple worker processes.\n\nAdditional concurrency strategies will hopefully be contributed in the future.\nIf you are interested in helping out, please let us know.\n\n#### More info: Threads on Fork Worker\n\nFor more information on the threads_on_fork worker, check out the\n[ThreadsOnFork Worker](https://github.com/nesquena/backburner/wiki/ThreadsOnFork-worker) documentation. Please note that the `ThreadsOnFork` worker does not work on Windows due to its lack of `fork`.\n\n#### More info: Threading Worker (thread-pool-based)\n\nConfiguration options for the Threading worker are similar to the threads_on_fork worker, sans the garbage option. When running via the `backburner` CLI, it's simplest to provide the queue names and maximum number of threads in the format \"{queue name}:{max threads in pool}[,{name}:{threads}]\":\n\n```\n$ bundle exec backburner -q queue1:4,queue2:4  # and then other options, like environment, pidfile, app root, etc. See docs for the CLI\n```\n\n### Default Queues\n\nWorkers can be easily restricted to processing only a specific set of queues as shown above. However, if you want a worker to\nprocess **all** queues instead, then you can leave the queue list blank.\n\nWhen you execute a worker without any queues specified, queues for known job queue class with `include Backburner::Queue` will be processed.\nTo access the list of known queue classes, you can use:\n\n```ruby\nBackburner::Worker.known_queue_classes\n# =\u003e [NewsletterJob, SomeOtherJob]\n```\n\nDynamic queues created by passing queue options **will not be processed** by a default worker. For this reason, you may want to take control over the default list of\nqueues processed when none are specified. To do this, you can use the `default_queues` class method:\n\n```ruby\nBackburner.default_queues.concat([\"foo\", \"bar\"])\n```\n\nThis will ensure that the _foo_ and _bar_ queues are processed by any default workers. You can also add job queue names with:\n\n```ruby\nBackburner.default_queues \u003c\u003c NewsletterJob.queue\n```\n\nThe `default_queues` stores the specific list of queues that should be processed by default by a worker.\n\n### Failures\n\nWhen a job fails in backburner (usually because an exception was raised), the job will be released\nand retried again until the `max_job_retries` configuration is reached.\n\n```ruby\nBackburner.configure do |config|\n  config.max_job_retries  = 3 # retry jobs 3 times\n  config.retry_delay      = 2 # wait 2 seconds in between retries\nend\n```\n\nNote the default `max_job_retries` is 0, meaning that by default **jobs are not retried**.\n\nAs jobs are retried, a progressively-increasing delay is added to give time for transient\nproblems to resolve themselves. This may be configured using `retry_delay_proc`. It expects\nan object that responds to `#call` and receives the value of `retry_delay` and the number\nof times the job has been retried already. The default is a cubic back-off, eg:\n\n```ruby\nBackburner.configure do |config|\n  config.retry_delay      = 2 # The minimum number of seconds a retry will be delayed\n  config.retry_delay_proc = lambda { |min_retry_delay, num_retries| min_retry_delay + (num_retries ** 3) }\nend\n```\n\nIf continued retry attempts fail, the job will be buried and can be 'kicked' later for inspection.\n\nYou can also setup a custom error handler for jobs using configure:\n\n```ruby\nBackburner.configure do |config|\n  config.on_error = lambda { |ex| Airbrake.notify(ex) }\nend\n```\n\nNow all backburner queue errors will appear on airbrake for deeper inspection.\n\nIf you wish to retry a job without logging an error (for example when handling transient issues in a cloud or service oriented environment), \nsimply raise a `Backburner::Job::RetryJob` error.\n\n### Logging\n\nLogging in backburner is rather simple. When a job is run, the log records that. When a job\nfails, the log records that. When any exceptions occur during processing, the log records that.\n\nBy default, the log will print to standard out. You can customize the log to output to any\nstandard logger by controlling the configuration option:\n\n```ruby\nBackburner.configure do |config|\n  config.logger = Logger.new(STDOUT)\nend\n```\n\nBe sure to check logs whenever things do not seem to be processing.\n\n### Hooks\n\nBackburner is highly extensible and can be tailored to your needs by using various hooks that\ncan be triggered across the job processing lifecycle.\nOften using hooks is much easier then trying to monkey patch the externals.\n\nCheck out [HOOKS.md](https://github.com/nesquena/backburner/blob/master/HOOKS.md) for a detailed overview on using hooks.\n\n### Workers in Production\n\nOnce you have Backburner setup in your application, starting workers is really easy. Once [beanstalkd](http://kr.github.com/beanstalkd/download.html)\nis installed, your best bet is to use the built-in rake task that comes with Backburner. Simply add the task to your Rakefile:\n\n```ruby\n# Rakefile\nrequire 'backburner/tasks'\n```\n\nand then you can start the rake task with:\n\n```bash\n$ rake backburner:work\n$ QUEUE=newsletter-sender,push-notifier rake backburner:work\n```\n\nThe best way to deploy these rake tasks is using a monitoring library. We suggest [God](https://github.com/mojombo/god/)\nwhich watches processes and ensures their stability. A simple God recipe for Backburner can be found in\n[examples/god](https://github.com/nesquena/backburner/blob/master/examples/god.rb).\n\n#### Command-Line Interface\n\nInstead of using the Rake tasks, you can use Backburner's command-line interface (CLI) – powered by the [Dante gem](https://github.com/nesquena/dante) – to launch daemonized workers. Several flags are available to control the process. Many of these are provided by Dante itself, such as flags for logging (`-l`), the process' PID (`-P`), whether to daemonize (`-d`) or kill a running process (`-k`). Backburner provides a few more:\n\n\n##### Queues (`-q`)\n\nControl which queues the worker will watch with the `-q` flag. Comma-separate multiple queue names and, if you're using the `ThreadsOnFork` worker, colon-separate the settings for thread limit, garbage limit and retries limit (eg. `send_mail:4:10:3`). See its [wiki page](https://github.com/nesquena/backburner/wiki/ThreadsOnFork-worker) for some more details.\n\n```ruby\nbackburner -q send_mail,create_thumbnail # You may need to use `bundle exec`\n```\n\n##### Boot an app (`-r`)\n\nLoad an app with the `-r` flag. Backburner supports automatic loading for both Rails and Padrino apps when started from the their root folder. However, you may point to a specific app's root using this flag, which is very useful when running workers from a service script.\n\n```ruby\npath=\"/var/www/my-app/current\"\nbackburner -r \"$path\"\n```\n\n##### Load an environment (`-e`)\n\nUse the `-e` flag to control which environment your app should use:\n\n```ruby\nenvironment=\"production\"  \nbackburner -e $environment\n```\n\n#### Reconnecting\n\nIn Backburner, if the beanstalkd connection is temporarily severed, several retries to establish the connection will be attempted.\nAfter several retries, if the connection is still not able to be made, a `Beaneater::NotConnected` exception will be raised.\nYou can manually catch this exception, and attempt another manual retry using `Backburner::Worker.retry_connection!`.\n\n### Web Front-end\n\nBe sure to check out the Sinatra-powered project [beanstalkd_view](https://github.com/denniskuczynski/beanstalkd_view)\nby [denniskuczynski](http://github.com/denniskuczynski) which provides an excellent overview of the tubes and\njobs processed by your beanstalk workers. An excellent addition to your Backburner setup.\n\n## Acknowledgements\n\n * [Nathan Esquenazi](https://github.com/nesquena) - Project maintainer\n * [Dave Myron](https://github.com/contentfree) - Multiple features and doc improvements\n * Kristen Tucker - Coming up with the gem name\n * [Tim Lee](https://github.com/timothy1ee), [Josh Hull](https://github.com/joshbuddy), [Nico Taing](https://github.com/Nico-Taing) - Helping me work through the idea\n * [Miso](http://gomiso.com) - Open-source friendly place to work\n * [Evgeniy Denisov](https://github.com/silentshade) - Multiple fixes and cleanups\n * [Andy Bakun](https://github.com/thwarted) - Fixes to how multiple beanstalkd instances are processed\n * [Renan T. Fernandes](https://github.com/ShadowBelmolve) - Added threads_on_fork worker\n * [Daniel Farrell](https://github.com/danielfarrell) - Added forking worker\n\n## Contributing\n\n1. Fork it\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Added some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create new Pull Request\n\n## References\n\nThe code in this project has been made in light of a few excellent projects:\n\n * [DelayedJob](https://github.com/collectiveidea/delayed_job)\n * [Resque](https://github.com/defunkt/resque)\n * [Stalker](https://github.com/han/stalker)\n\nThanks to these projects for inspiration and certain design and implementation decisions.\n\n## Links\n\n * Code: `git clone git://github.com/nesquena/backburner.git`\n * Home: \u003chttp://github.com/nesquena/backburner\u003e\n * Docs: \u003chttp://rdoc.info/github/nesquena/backburner/master/frames\u003e\n * Bugs: \u003chttp://github.com/nesquena/backburner/issues\u003e\n * Gems: \u003chttp://gemcutter.org/gems/backburner\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnesquena%2Fbackburner","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnesquena%2Fbackburner","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnesquena%2Fbackburner/lists"}