backburner 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
@@ -0,0 +1,10 @@
1
+ # http://about.travis-ci.org/docs/user/build-configuration/
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - rbx-19mode
7
+ gemfile: Gemfile
8
+ notifications:
9
+ recipients:
10
+ - nesquena@gmail.com
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in backburner.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Nathan Esquenazi
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,205 @@
1
+ # Backburner
2
+
3
+ Backburner is a beanstalkd-powered job queue designed to be as simple and easy to use as possible.
4
+ You can create background jobs, place those on specialized queues and process them later.
5
+
6
+ Processing background jobs reliably has never been easier. Backburner works with any ruby-based
7
+ web framework but is well-suited for use with [Sinatra](http://sinatrarb.com) and [Padrino](http://padrinorb.com).
8
+
9
+ If you want to use beanstalk for job processing, consider using Backburner. Backburner is heavily inspired by Resque and DelayedJob.
10
+ Backburner can be a persistent queue if the beanstalk persistence mode is enabled, supports priority, delays, and timeouts.
11
+ Backburner stores jobs as simple JSON payloads.
12
+
13
+ ## Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ gem 'backburner'
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install backburner
26
+
27
+ ## Configuration ##
28
+
29
+ Backburner is extremely simple to setup. Just configure basic settings for backburner:
30
+
31
+ ```ruby
32
+ Backburner.configure do |config|
33
+ config.beanstalk_url = "beanstalk://127.0.0.1"
34
+ config.tube_namespace = "some.app.production"
35
+ config.on_error = lambda { |e| puts e }
36
+ config.default_priority = 65536
37
+ config.respond_timeout = 120
38
+ end
39
+ ```
40
+
41
+ ## Usage
42
+
43
+ Backburner allows you to create jobs and place them on a beanstalk queue, and later pull those jobs off the queue and
44
+ process them asynchronously.
45
+
46
+ ### Enqueuing Jobs ###
47
+
48
+ At the core, Backburner is about jobs that can be processed. Jobs are simple ruby objects with a method defined named `perform`.
49
+
50
+ Any object which responds to `perform` can be queued as a job. Job objects are queued as JSON to be later processed by a task runner.
51
+ Here's an example:
52
+
53
+ ```ruby
54
+ class NewsletterJob
55
+ include Backburner::Queue
56
+ queue "newsletter"
57
+
58
+ def self.perform(email, body)
59
+ NewsletterMailer.deliver_text_to_email(email, body)
60
+ end
61
+ end
62
+ ```
63
+
64
+ Notice that you must include the `Backburner::Queue` module and that you can set a `queue` name within the job automatically.
65
+ Jobs can then be enqueued using:
66
+
67
+ ```ruby
68
+ Backburner.enqueue NewsletterJob, 'lorem ipsum...', 5
69
+ ```
70
+
71
+ `Backburner.enqueue` accepts first a ruby object that supports `perform` and then a series of parameters
72
+ to that object's `perform` method. The queue name used by default is the normalized class name (i.e `{namespace}.newsletter-job`)
73
+ if not otherwise specified.
74
+
75
+ ### Simple Async Jobs ###
76
+
77
+ In addition to defining custom jobs, a job can also be enqueued by invoking the `async` method on any object which
78
+ includes `Backburner::Performable`.
79
+
80
+ ```ruby
81
+ class User
82
+ include Backburner::Performable
83
+
84
+ def activate(device_id)
85
+ @device = Device.find(device_id)
86
+ # ...
87
+ end
88
+ end
89
+
90
+ @user = User.first
91
+ @user.async(:pri => 1000, :ttr => 100, :queue => "user.activate").activate(@device.id)
92
+ ```
93
+
94
+ This will automatically enqueue a job that will run `activate` with the specified argument for that user record.
95
+ The queue name used by default is the normalized class name (i.e `{namespace}.user`) if not otherwise specified.
96
+ Note you are able to pass `pri`, `ttr`, `delay` and `queue` directly as options into `async`.
97
+
98
+ ### Working Jobs
99
+
100
+ Backburner workers are processes that run forever handling jobs that get reserved. Starting a worker in ruby code is simple:
101
+
102
+ ```ruby
103
+ Backburner.work
104
+ ```
105
+
106
+ This will process jobs in all queues but you can also restrict processing to specific queues:
107
+
108
+ ```ruby
109
+ Backburner.work('newsletter_sender')
110
+ ```
111
+
112
+ The Backburner worker also exists as a rake task:
113
+
114
+ ```ruby
115
+ require 'backburner/tasks'
116
+ ```
117
+
118
+ so you can run:
119
+
120
+ ```
121
+ $ QUEUES=newsletter-sender,push-message rake backburner:work
122
+ ```
123
+
124
+ You can also run the backburner binary for a convenient worker:
125
+
126
+ ```
127
+ bundle exec backburner newsletter-sender,push-message -d -P /var/run/backburner.pid -l /var/log/backburner.log
128
+ ```
129
+
130
+ This will daemonize the worker and store the pid and logs automatically.
131
+
132
+ ### Default Queues
133
+
134
+ Workers can be easily restricted to processing only a specific set of queues as shown above. However, if you want a worker to
135
+ process **all** queues instead, then you can leave the queue list blank.
136
+
137
+ When you execute a worker without queues specified, any queue for a known job queue class with `include Backburner::Queue` will be processed. To access the list of known
138
+ queue classes, you can use:
139
+
140
+ ```ruby
141
+ Backburner::Worker.known_queue_classes
142
+ # => [NewsletterJob, SomeOtherJob]
143
+ ```
144
+
145
+ Dynamic 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
146
+ queues processed when none are specified. To do this, you can use the `default_queues` class method:
147
+
148
+ ```ruby
149
+ Backburner.default_queues.concat(["foo", "bar"])
150
+ ```
151
+
152
+ This will ensure that the _foo_ and _bar_ queues are processed by default. You can also add job queue names:
153
+
154
+ ```ruby
155
+ Backburner.default_queues << NewsletterJob.queue
156
+ ```
157
+
158
+ The `default_queues` stores the specific list of queues that should be processed by default by a worker.
159
+
160
+ ### Failures
161
+
162
+ You can setup the error handler for jobs using configure:
163
+
164
+ ```ruby
165
+ Backburner.configure do |config|
166
+ config.on_error = lambda { |ex| Airbrake.notify(ex) }
167
+ end
168
+ ```
169
+
170
+ Now all beanstalk queue errors will show up on airbrake.
171
+ If a job fails in beanstalk, the job is automatically buried and must be 'kicked' later.
172
+
173
+ ### Logging
174
+
175
+ Right now, all logging happens to standard out and can be piped to a file or any other output manually. More on logging coming later.
176
+
177
+ ### Front-end Monitoring
178
+
179
+ To be completed is an admin dashboard that provides insight into beanstalk jobs via a simple Sinatra front-end. Coming soon.
180
+
181
+ ## Why Backburner?
182
+
183
+ To be filled in. DelayedJob, Resque, Stalker, et al.
184
+
185
+ ## Acknowledgements
186
+
187
+ * Nathan Esquenazi - Project maintainer
188
+ * Kristen Tucker - Coming up with the gem name
189
+ * [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
190
+ * [Miso](http://gomiso.com) - Open-source friendly place to work
191
+
192
+ ## Contributing
193
+
194
+ 1. Fork it
195
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
196
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
197
+ 4. Push to the branch (`git push origin my-new-feature`)
198
+ 5. Create new Pull Request
199
+
200
+ ## References
201
+
202
+ The code in this project has been adapted from a few excellent projects:
203
+
204
+ * [DelayedJob](https://github.com/collectiveidea/delayed_job)
205
+ * [Stalker](https://github.com/han/stalker)
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'rake/testtask'
4
+ # require 'yard'
5
+
6
+ task :test do
7
+ Rake::TestTask.new do |t|
8
+ t.libs.push "lib"
9
+ t.test_files = FileList[File.expand_path('../test/**/*_test.rb', __FILE__)]
10
+ t.verbose = true
11
+ end
12
+ end
13
+
14
+ # task :doc do
15
+ # YARD::CLI::Yardoc.new.run
data/TODO ADDED
@@ -0,0 +1,5 @@
1
+ - Better way to enummerate job names in worker (right now using the tubes that exist but they may not exist even tho they will)
2
+ - Use a better way to aggregate tube names for different jobs
3
+ - Front-end in sinatra for viewing beanstalk jobs
4
+ - Better logging
5
+ - Better error handling (failures, retries)
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/backburner/version', __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.authors = ["Nathan Esquenazi"]
6
+ s.email = ["nesquena@gmail.com"]
7
+ s.description = %q{Beanstalk background job processing made easy}
8
+ s.summary = %q{Reliable beanstalk background job processing made easy for Ruby and Sinatra}
9
+ s.homepage = "http://github.com/nesquena/backburner"
10
+
11
+ s.files = `git ls-files`.split($\)
12
+ s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
14
+ s.name = "backburner"
15
+ s.require_paths = ["lib"]
16
+ s.version = Backburner::VERSION
17
+
18
+ s.add_runtime_dependency(%q<beanstalk-client>, [">= 0"])
19
+ s.add_runtime_dependency(%q<json_pure>, [">= 0"])
20
+ s.add_runtime_dependency(%q<dante>)
21
+
22
+ s.add_development_dependency 'rake'
23
+ s.add_development_dependency 'minitest'
24
+ s.add_development_dependency 'mocha'
25
+ end
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'backburner'
4
+ require 'dante'
5
+
6
+ # bundle exec backburner foo,bar
7
+ queues = (ARGV.first ? ARGV.first.split(',') : nil) rescue nil
8
+ Dante.run('backburner') do |opts|
9
+ Backburner.work(queues)
10
+ end
@@ -0,0 +1,25 @@
1
+ $:.unshift "lib"
2
+ require 'backburner'
3
+
4
+ # Define ruby job
5
+ class TestJob
6
+ include Backburner::Queue
7
+ # queue "test-job"
8
+
9
+ def self.perform(value, user)
10
+ puts "[TestJob] Running perform with args: [#{value}, #{user}]"
11
+ end
12
+ end
13
+
14
+ # Configure Backburner
15
+ Backburner.configure do |config|
16
+ config.beanstalk_url = "beanstalk://127.0.0.1"
17
+ config.tube_namespace = "demo.production"
18
+ end
19
+
20
+ # Enqueue tasks
21
+ Backburner.enqueue TestJob, 5, 3
22
+ Backburner.enqueue TestJob, 10, 6
23
+
24
+ # Work tasks
25
+ Backburner.work("test-job")
@@ -0,0 +1,60 @@
1
+ $:.unshift "lib"
2
+ require 'backburner'
3
+
4
+ module Tester
5
+ class TestJob
6
+ include Backburner::Queue
7
+ queue "test.job"
8
+
9
+ def self.perform(value, user)
10
+ p [value, user]
11
+ end
12
+ end
13
+
14
+ class UserModel
15
+ include Backburner::Performable
16
+
17
+ attr_accessor :id, :name
18
+
19
+ def self.first
20
+ self.find(3, "John")
21
+ end
22
+
23
+ def self.find(id, name="Fetched")
24
+ self.new(id, name)
25
+ end
26
+
27
+ def initialize(id, name)
28
+ @id, @name = id, name
29
+ end
30
+
31
+ def hello(x, y)
32
+ puts "Instance #{x} and #{y} and my id is #{id}"
33
+ end
34
+
35
+ def self.foo(x, y)
36
+ puts "Class #{x} and #{y}"
37
+ end
38
+ end
39
+ end
40
+
41
+ # connection = Backburner::Connection.new("beanstalk://localhost")
42
+
43
+ Backburner.configure do |config|
44
+ config.beanstalk_url = "beanstalk://127.0.0.1"
45
+ config.tube_namespace = "myblog.production"
46
+ end
47
+
48
+ # p Backburner.configuration.beanstalk_url
49
+ # p Backburner::Worker.connection
50
+
51
+ Backburner.enqueue Tester::TestJob, 5, 3
52
+ Backburner.enqueue Tester::TestJob, 10, 6
53
+ @user = Tester::UserModel.first
54
+ @user.async.hello("foo", "bar")
55
+ Tester::UserModel.async.foo("bar", "baz")
56
+
57
+ Backburner.default_queues.concat([Tester::TestJob.queue, Tester::UserModel.queue])
58
+ Backburner.work
59
+ # Backburner.work("test.job")
60
+ # Backburner.work("tester/user-model")
@@ -0,0 +1,43 @@
1
+ $:.unshift "lib"
2
+ require 'backburner'
3
+
4
+ class User
5
+ include Backburner::Performable
6
+ attr_accessor :id, :name
7
+
8
+ def self.first
9
+ User.find(3, "John")
10
+ end
11
+
12
+ def self.find(id, name="Fetched")
13
+ User.new(id, name)
14
+ end
15
+
16
+ def initialize(id, name)
17
+ @id, @name = id, name
18
+ end
19
+
20
+ def hello(x, y)
21
+ puts "User(id=#{id}) #hello args: [#{x}, #{y}] (Instance method)"
22
+ end
23
+
24
+ def self.foo(x, y)
25
+ puts "User #foo args [#{x}, #{y}] (Class method)"
26
+ end
27
+ end
28
+
29
+ # Configure Backburner
30
+ Backburner.configure do |config|
31
+ config.beanstalk_url = "beanstalk://127.0.0.1"
32
+ config.tube_namespace = "demo.production"
33
+ config.on_error = lambda { |e| puts "HEY!!! #{e.class}" }
34
+ end
35
+
36
+ # Enqueue tasks
37
+ @user = User.first
38
+ @user.async(:pri => 1000).hello("foo", "bar")
39
+ User.async.foo("bar", "baz")
40
+
41
+ # Run work
42
+ # Backburner.default_queues << "user"
43
+ Backburner.work