ayl-beanstalk 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,22 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+ gem 'ayl', ">= 0.1.0"
6
+ gem 'beanstalk-client', ">= 1.1.0"
7
+ gem 'daemons', ">= 1.1.0"
8
+
9
+ # Add dependencies to develop your gem here.
10
+ # Include everything needed to run rake, tests, features, etc.
11
+ group :development do
12
+ gem "rspec", ">= 2.3.0"
13
+ gem "bundler", ">= 1.0.0"
14
+ gem "jeweler", ">= 1.6.4"
15
+ gem "rcov", ">= 0"
16
+ gem 'pry'
17
+ end
18
+
19
+ group :test do
20
+ gem 'rails', ">= 3.0.0"
21
+ gem 'pry'
22
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,125 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ actionmailer (3.1.2)
5
+ actionpack (= 3.1.2)
6
+ mail (~> 2.3.0)
7
+ actionpack (3.1.2)
8
+ activemodel (= 3.1.2)
9
+ activesupport (= 3.1.2)
10
+ builder (~> 3.0.0)
11
+ erubis (~> 2.7.0)
12
+ i18n (~> 0.6)
13
+ rack (~> 1.3.5)
14
+ rack-cache (~> 1.1)
15
+ rack-mount (~> 0.8.2)
16
+ rack-test (~> 0.6.1)
17
+ sprockets (~> 2.1.0)
18
+ activemodel (3.1.2)
19
+ activesupport (= 3.1.2)
20
+ builder (~> 3.0.0)
21
+ i18n (~> 0.6)
22
+ activerecord (3.1.2)
23
+ activemodel (= 3.1.2)
24
+ activesupport (= 3.1.2)
25
+ arel (~> 2.2.1)
26
+ tzinfo (~> 0.3.29)
27
+ activeresource (3.1.2)
28
+ activemodel (= 3.1.2)
29
+ activesupport (= 3.1.2)
30
+ activesupport (3.1.2)
31
+ multi_json (~> 1.0)
32
+ arel (2.2.1)
33
+ ayl (0.1.0)
34
+ beanstalk-client (1.1.1)
35
+ builder (3.0.0)
36
+ coderay (0.9.8)
37
+ daemons (1.1.4)
38
+ diff-lcs (1.1.3)
39
+ erubis (2.7.0)
40
+ git (1.2.5)
41
+ hike (1.2.1)
42
+ i18n (0.6.0)
43
+ jeweler (1.6.4)
44
+ bundler (~> 1.0)
45
+ git (>= 1.2.5)
46
+ rake
47
+ json (1.6.1)
48
+ mail (2.3.0)
49
+ i18n (>= 0.4.0)
50
+ mime-types (~> 1.16)
51
+ treetop (~> 1.4.8)
52
+ method_source (0.6.7)
53
+ ruby_parser (>= 2.3.1)
54
+ mime-types (1.17.2)
55
+ multi_json (1.0.3)
56
+ polyglot (0.3.3)
57
+ pry (0.9.7.4)
58
+ coderay (~> 0.9.8)
59
+ method_source (~> 0.6.7)
60
+ ruby_parser (>= 2.3.1)
61
+ slop (~> 2.1.0)
62
+ rack (1.3.5)
63
+ rack-cache (1.1)
64
+ rack (>= 0.4)
65
+ rack-mount (0.8.3)
66
+ rack (>= 1.0.0)
67
+ rack-ssl (1.3.2)
68
+ rack
69
+ rack-test (0.6.1)
70
+ rack (>= 1.0)
71
+ rails (3.1.2)
72
+ actionmailer (= 3.1.2)
73
+ actionpack (= 3.1.2)
74
+ activerecord (= 3.1.2)
75
+ activeresource (= 3.1.2)
76
+ activesupport (= 3.1.2)
77
+ bundler (~> 1.0)
78
+ railties (= 3.1.2)
79
+ railties (3.1.2)
80
+ actionpack (= 3.1.2)
81
+ activesupport (= 3.1.2)
82
+ rack-ssl (~> 1.3.2)
83
+ rake (>= 0.8.7)
84
+ rdoc (~> 3.4)
85
+ thor (~> 0.14.6)
86
+ rake (0.9.2.2)
87
+ rcov (0.9.11)
88
+ rdoc (3.11)
89
+ json (~> 1.4)
90
+ rspec (2.7.0)
91
+ rspec-core (~> 2.7.0)
92
+ rspec-expectations (~> 2.7.0)
93
+ rspec-mocks (~> 2.7.0)
94
+ rspec-core (2.7.1)
95
+ rspec-expectations (2.7.0)
96
+ diff-lcs (~> 1.1.2)
97
+ rspec-mocks (2.7.0)
98
+ ruby_parser (2.3.1)
99
+ sexp_processor (~> 3.0)
100
+ sexp_processor (3.0.8)
101
+ slop (2.1.0)
102
+ sprockets (2.1.1)
103
+ hike (~> 1.2)
104
+ rack (~> 1.0)
105
+ tilt (~> 1.1, != 1.3.0)
106
+ thor (0.14.6)
107
+ tilt (1.3.3)
108
+ treetop (1.4.10)
109
+ polyglot
110
+ polyglot (>= 0.3.1)
111
+ tzinfo (0.3.31)
112
+
113
+ PLATFORMS
114
+ ruby
115
+
116
+ DEPENDENCIES
117
+ ayl (>= 0.1.0)
118
+ beanstalk-client (>= 1.1.0)
119
+ bundler (>= 1.0.0)
120
+ daemons (>= 1.1.0)
121
+ jeweler (>= 1.6.4)
122
+ pry
123
+ rails (>= 3.0.0)
124
+ rcov
125
+ rspec (>= 2.3.0)
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 j0hnds@gmail.com
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,20 @@
1
+ = ayl-beanstalk
2
+
3
+ This gem provides a reference implementation of a beanstalk Engine for the
4
+ {ayl}[https://github.com/j0hnds/ayl] gem.
5
+
6
+ == Contributing to ayl-beanstalk
7
+
8
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
9
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
10
+ * Fork the project
11
+ * Start a feature/bugfix branch
12
+ * Commit and push until you are happy with your contribution
13
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
14
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
15
+
16
+ == Copyright
17
+
18
+ Copyright (c) 2011 j0hnds@gmail.com. See LICENSE.txt for
19
+ further details.
20
+
data/Rakefile ADDED
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "ayl-beanstalk"
18
+ gem.homepage = "http://github.com/j0hnds/ayl-beanstalk"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Ayl extension to provide beanstalk support.}
21
+ gem.description = %Q{Ayl extension to provide beanstalk support.}
22
+ gem.email = "j0hnds@gmail.com"
23
+ gem.authors = ["j0hnds@gmail.com"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rspec/core'
29
+ require 'rspec/core/rake_task'
30
+ RSpec::Core::RakeTask.new(:spec) do |spec|
31
+ spec.pattern = FileList['spec/**/*_spec.rb']
32
+ end
33
+
34
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
35
+ spec.pattern = 'spec/**/*_spec.rb'
36
+ spec.rcov = true
37
+ end
38
+
39
+ task :default => :spec
40
+
41
+ require 'rdoc/task'
42
+ Rake::RDocTask.new do |rdoc|
43
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
44
+
45
+ rdoc.rdoc_dir = 'rdoc'
46
+ rdoc.title = "ayl-beanstalk #{version}"
47
+ rdoc.rdoc_files.include('README*')
48
+ rdoc.rdoc_files.include('lib/**/*.rb')
49
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/bin/ayl_beanstalk ADDED
@@ -0,0 +1,281 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Use this script to look at the current beanstalk information. For help
4
+ # running this script, enter 'beastalk_info.rb --help' on the command line.
5
+ #
6
+ require 'date'
7
+ require 'optparse'
8
+ require 'beanstalk-client'
9
+
10
+ SLEEP_COMMAND = {
11
+ :type => :rails,
12
+ :code => 'Kernel.sleep(20)' # This message will cause the worker to sleep for 20 seconds
13
+ }
14
+
15
+ #
16
+ # This class provides the commands for the script. Each public instance method
17
+ # on the class is exposed as a command by the script. So, for example, if the
18
+ # user specifies 'beanstalk_info.rb statistics' on the command-line, the script
19
+ # will invoke the BeanstalkCommander#statistics method.
20
+ #
21
+ # When the user asks the script for help ('beanstalk_info.rb --help'), the help
22
+ # implementation will ask for the public instance methods for the BeanstalkCommander
23
+ # class so that we can present the user with the valid commands
24
+ #
25
+ class BeanstalkCommander
26
+
27
+ def initialize(host, port, tube)
28
+ @host = host
29
+ @port = port
30
+ @tube = tube
31
+ end
32
+
33
+ #
34
+ # Lists the statistics for the specified job number
35
+ #
36
+ def job_statistics(job_number)
37
+ raise "Must specify a job number to get the statistics for" unless job_number
38
+ format_statistics(pool.open_connections.first.job_stats(job_number))
39
+ end
40
+
41
+ #
42
+ # Lists the statistics for the current tube on beanstalk
43
+ #
44
+ def tube_statistics(*args)
45
+ puts "Statistics for Tube: #{@tube}"
46
+ format_statistics(pool.stats_tube(@tube))
47
+ end
48
+
49
+ #
50
+ # Lists the overall statistics for beanstalk
51
+ #
52
+ def statistics(*args)
53
+ puts "Overall Statistics"
54
+ puts "------------------"
55
+ format_statistics(pool.stats)
56
+ end
57
+
58
+ #
59
+ # Lists the tubes active on beanstalk
60
+ #
61
+ def list_tubes(*args)
62
+ tubes = pool.list_tubes
63
+ puts "Tubes in use"
64
+ puts "------------"
65
+ tubes.each_pair do | host, tubes |
66
+ puts host
67
+ tubes.each { | tube | puts " - #{tube}" }
68
+ end
69
+ end
70
+
71
+ #
72
+ # Displays the job information for the specified job id without
73
+ # reserving the job or removing it from the queue.
74
+ #
75
+ def peek_job(job_number)
76
+ raise "Must specify a job number to peek" unless job_number
77
+ job = pool.peek_job(job_number)
78
+ format_job(job)
79
+ end
80
+
81
+ #
82
+ # Deletes the job with the specified job id.
83
+ #
84
+ def delete(job_number)
85
+ raise "Must specify a job number to delete" unless job_number
86
+ pool.open_connections.first.delete(job_number)
87
+ end
88
+
89
+ #
90
+ # Displays the most current job on the ready queue
91
+ #
92
+ def peek_ready(*args)
93
+ pool.use(@tube)
94
+ job = pool.peek_ready
95
+ format_job(job)
96
+ end
97
+
98
+ #
99
+ # Kick any buried/delayed jobs in te queue
100
+ #
101
+ def kick(*args)
102
+ pool.use(@tube)
103
+ pool.open_connections.first.kick 1
104
+ end
105
+
106
+ #
107
+ # Displays the most current job on the delayed queue
108
+ #
109
+ def peek_delayed(*args)
110
+ pool.use(@tube)
111
+ job = pool.peek_delayed
112
+ format_job(job)
113
+ end
114
+
115
+ #
116
+ # Displays the most current job on the buried queue
117
+ #
118
+ def peek_buried(*args)
119
+ pool.use(@tube)
120
+ job = pool.peek_buried
121
+ format_job(job)
122
+ end
123
+
124
+ #
125
+ # Puts a generic job on the queue (job is specified on the command line)
126
+ #
127
+ def put_job(job_body)
128
+ raise "Must specify a job body to put" unless job_body
129
+ puts "Putting (#{job_body}) on tube: #{@tube}"
130
+ pool.use(@tube)
131
+ pool.put(job_body)
132
+ puts "Job was put"
133
+ end
134
+
135
+ def put_ayl_job(job_body)
136
+ raise "Must specify a job body to put" unless job_body
137
+ puts "Putting (#{job_body}) on tube: #{@tube}"
138
+ pool.put({:type => :ayl, :code => job_body}.to_yaml)
139
+ puts "Job was put"
140
+ end
141
+
142
+ def put_sleep_job(*args)
143
+ puts "Putting job on tube '#{@tube}' that will sleep for 20 seconds."
144
+ pool.use(@tube)
145
+ pool.put(SLEEP_COMMAND.to_yaml)
146
+ end
147
+
148
+ #
149
+ # Reserves the current job on the queue, displays it, and removes it from the
150
+ # queue. The operation is performed against the current queue.
151
+ #
152
+ def eat_job(*args)
153
+ # Reserve the next job on the queue
154
+ pool.watch(@tube)
155
+ job = pool.reserve(10)
156
+ raise "No job to reserve" unless job
157
+ puts "Reserved job"
158
+ format_job(job)
159
+ job.delete
160
+ puts "Deleted job"
161
+ end
162
+
163
+ #
164
+ # General purpose tube cleaning mechanism. This allows you to move all the jobs
165
+ # from one tube to another within beanstalk.
166
+ # The tube specified on the command line (-t tube), will be used as the 'from-tube' and
167
+ # the argument to the move_jobs command is the 'to-tube'. When done, you will be a
168
+ # a time-out error (because the 'reserve' command timed out without finding a job).
169
+ #
170
+ # It is fast and awesome.
171
+ #
172
+ def move_jobs(to_tube)
173
+ pool.watch(@tube)
174
+ pool.use(to_tube)
175
+ while true
176
+ job = pool.reserve(0)
177
+ if job
178
+ pool.put(job.body)
179
+ job.delete
180
+ else
181
+ break
182
+ end
183
+ end
184
+ end
185
+
186
+ private
187
+
188
+ #
189
+ # Returns the connected beanstalk pool
190
+ #
191
+ def pool
192
+ @pool ||= Beanstalk::Pool.new(["#{@host}:#{@port}"])
193
+ end
194
+
195
+ #
196
+ # Formats the specified job. Can handle the job returned as a hash and as
197
+ # a job object.
198
+ #
199
+ def format_job(job)
200
+ if job.nil?
201
+ puts "No job..."
202
+ elsif job.is_a?(Hash)
203
+ job.each_pair do | host, job |
204
+ format_job(job)
205
+ end
206
+ else
207
+ puts "Job: #{job.id}: #{job.body}"
208
+ end
209
+ end
210
+
211
+ #
212
+ # Standardized statistics formatting for both tube and general statistics.
213
+ #
214
+ def format_statistics(statistics)
215
+ statistics.keys.sort.each do | key |
216
+ puts format("%-25s => %13s", key, statistics[key]) if statistics[key].is_a?(Fixnum)
217
+ puts format("%-25s => %-13s", key, statistics[key]) if statistics[key].is_a?(String)
218
+ end
219
+ end
220
+ end
221
+
222
+ BEANSTALK_HOST_DEFAULT = 'localhost'
223
+ BEANSTALK_PORT_DEFAULT = 11300
224
+ DEFAULT_APP_TUBE_NAME = "default"
225
+
226
+ options = {}
227
+
228
+ # Set up the options supported by the script
229
+ optparse = OptionParser.new do | opts |
230
+
231
+ # Set a banner, displayed at the top of the help screen
232
+ opts.banner = "Usage: #{$0} [options] command"
233
+
234
+ options[:host] = BEANSTALK_HOST_DEFAULT
235
+ opts.on '-h', '--host HOST', "Specify the host running beanstalk. Default (#{BEANSTALK_HOST_DEFAULT})" do | host |
236
+ options[:host] = host
237
+ end
238
+
239
+ options[:port] = BEANSTALK_PORT_DEFAULT
240
+ opts.on '-p', '--port PORT', "Specify the beanstalk port number. Default (#{BEANSTALK_PORT_DEFAULT})" do | port |
241
+ options[:port] = port.to_i
242
+ end
243
+
244
+ options[:tube] = DEFAULT_APP_TUBE_NAME
245
+ opts.on '-t', '--tube TUBE', "Specify the tube name. Default (#{DEFAULT_APP_TUBE_NAME})" do | tube |
246
+ options[:tube] = tube
247
+ end
248
+
249
+ opts.on '-h', '--help', 'Display the help message' do
250
+ puts opts
251
+ puts
252
+ puts "Valid Commands: "
253
+ # The false parameter in the instance_methods call is used to eliminate methods from the
254
+ # super-classes.
255
+ BeanstalkCommander.instance_methods(false).each do | command |
256
+ puts " - #{command}"
257
+ end
258
+ puts
259
+ exit
260
+ end
261
+
262
+ end
263
+
264
+ # Parse out the command line
265
+ optparse.parse!
266
+
267
+ begin
268
+ beanstalker = BeanstalkCommander.new(options[:host],
269
+ options[:port],
270
+ options[:tube])
271
+
272
+ raise "Must specify a command to execute." if ARGV.empty?
273
+ command = ARGV.first
274
+ raise "Invalid command: #{command}" unless beanstalker.respond_to?(command)
275
+
276
+ arguments = ARGV[1..-1]
277
+ beanstalker.send(command, *arguments)
278
+ rescue Exception => ex
279
+ puts "Error: #{ex.message}"
280
+ exit
281
+ end
data/bin/ayl_worker ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require 'ayl-beanstalk/command_line'
4
+
5
+ BASE_EXIT_CODE = 64
6
+ NO_APP_PATH_SPECIFIED = BASE_EXIT_CODE + 0
7
+
8
+ options = Ayl::CommandLine.parse!
9
+
10
+ if options[:app_path].nil?
11
+ puts "Must specify an application path"
12
+ exit(NO_APP_PATH_SPECIFIED)
13
+ end
14
+
15
+ if options[:rails_app]
16
+ require 'rails'
17
+ ENV['RAILS_ENV'] = options[:env]
18
+ end
19
+
20
+ require File.join(options[:app_path], options[:app_require])
21
+
22
+ Ayl::MessageOptions.default_queue_name = options[:tube]
23
+
24
+ worker = Ayl::Engine.get_active_engine.worker
25
+ worker.eval_binding = binding
26
+
27
+ worker.process_messages
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ require 'daemons'
3
+ require 'ayl-beanstalk/command_line'
4
+
5
+ sdir = File.dirname(File.absolute_path($0))
6
+ sname = File.basename($0).gsub('_control', '')
7
+ spath = File.join(sdir, sname)
8
+
9
+ options = Ayl::CommandLine.parse! Ayl::CommandLine.grab_app_arguments
10
+
11
+ raise "Must specify the path to the PID file" if options[:pid_path].nil?
12
+ raise "PID path does not exist" if !File.exists?(options[:pid_path])
13
+
14
+ Daemons.run(spath, :log_dir => '/tmp', :log_output => true, :dir_mode => :normal, :dir => options[:pid_path])
@@ -0,0 +1,5 @@
1
+ require 'ayl'
2
+ require 'beanstalk-client'
3
+ require 'ayl-beanstalk/pool'
4
+ require 'ayl-beanstalk/engine'
5
+ require 'ayl-beanstalk/worker'
@@ -0,0 +1,69 @@
1
+ require 'optparse'
2
+
3
+ module Ayl
4
+
5
+ module CommandLine
6
+
7
+ BEANSTALK_TUBE_DEFAULT = 'default'
8
+ APP_REQUIRE_DEFAULT = 'config/environment'
9
+ RAILS_ENVIRONMENT_DEFAULT = 'production'
10
+
11
+ MARKER = '--'
12
+
13
+ def self.grab_app_arguments(argv=ARGV)
14
+ marker_index = argv.index(MARKER)
15
+ raise "No argument marker found!" if marker_index.nil?
16
+ argv[marker_index + 1..-1]
17
+ end
18
+
19
+ def self.parse!(argv=ARGV)
20
+ {}.tap do | options |
21
+
22
+ optparse = OptionParser.new do | opts |
23
+
24
+ # Set a banner, displayed at the top of the help screen.
25
+ opts.banner = "Usage: #{$0} [options]"
26
+
27
+ options[:tube] = BEANSTALK_TUBE_DEFAULT
28
+ opts.on '-t', '--tube TUBE', "Specify the beanstalk tube to listen to. Default (#{BEANSTALK_TUBE_DEFAULT})." do |tube|
29
+ options[:tube] = tube
30
+ end
31
+
32
+ options[:env] = RAILS_ENVIRONMENT_DEFAULT
33
+ opts.on '-e', '--environment ENVIRONMENT', "Specify the Rails environment to use" do |environment|
34
+ options[:env] = environment
35
+ end
36
+
37
+ options[:app_path] = nil
38
+ opts.on '-a', '--app-path APP_PATH', "Specify the path to the rails app" do |app_path|
39
+ options[:app_path] = app_path
40
+ end
41
+
42
+ options[:rails_app] = false
43
+ opts.on '-r', '--rails', "Indicate that we are starting a rails application" do
44
+ options[:rails_app] = true
45
+ end
46
+
47
+ options[:app_require] = APP_REQUIRE_DEFAULT
48
+ opts.on '-c', '--require APP_REQUIRE', "The file to require when the worker starts up" do | app_require |
49
+ options[:app_require] = app_require
50
+ end
51
+
52
+ opts.on '-p', '--pid-path PID_PATH', "The path to the pid file" do | pid_path |
53
+ options[:pid_path] = pid_path
54
+ end
55
+
56
+ opts.on '-h', '--help', 'Display the help message' do
57
+ puts opts
58
+ exit(0)
59
+ end
60
+ end
61
+
62
+ optparse.parse!(argv)
63
+ end # End of .tap
64
+
65
+ end
66
+
67
+ end
68
+
69
+ end
@@ -0,0 +1,50 @@
1
+ module Ayl
2
+
3
+ module Beanstalk
4
+
5
+ class Engine
6
+ include Ayl::Logging
7
+ include Ayl::Beanstalk::Pool
8
+
9
+ def initialize(host='localhost', port=11300)
10
+ logger.info "#{self.class.name}.initialize(#{host.inspect}, #{port})"
11
+ @host = host
12
+ @port = port
13
+ end
14
+
15
+ def asynchronous?() true end
16
+
17
+ def is_connected?
18
+ connected = true
19
+ begin
20
+ pool
21
+ rescue ::Beanstalk::NotConnected => ex
22
+ logger.error "#{self.class.name} not connected error: #{ex}"
23
+ connected = false
24
+ end
25
+ connected
26
+ end
27
+
28
+ def submit(message)
29
+ log_call(:submit) do
30
+ begin
31
+ pool.use(message.options.queue_name)
32
+ code = message.to_rrepr
33
+ logger.info "#{self.class.name} submitting '#{code}' to tube '#{message.options.queue_name}'"
34
+ pool.yput(message.to_hash, message.options.priority, message.options.delay, message.options.time_to_run)
35
+ rescue Exception => ex
36
+ logger.error "Error submitting message to beanstalk: #{ex}"
37
+ end
38
+ end
39
+ end
40
+
41
+ def worker
42
+ Ayl::Beanstalk::Worker.new(@host, @port)
43
+ end
44
+
45
+ end
46
+
47
+
48
+ end
49
+
50
+ end
@@ -0,0 +1,15 @@
1
+ module Ayl
2
+
3
+ module Beanstalk
4
+
5
+ module Pool
6
+
7
+ def pool
8
+ @pool ||= ::Beanstalk::Pool.new([ "#{@host}:#{@port}" ])
9
+ end
10
+
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,46 @@
1
+ module Ayl
2
+
3
+ module Beanstalk
4
+
5
+ class Worker < Ayl::Worker
6
+ include Ayl::Logging
7
+ include Ayl::Beanstalk::Pool
8
+
9
+ def initialize(host='localhost', port=11300)
10
+ logger.info "#{self.class.name}.initialize(#{host.inspect}, #{port})"
11
+ @host = host
12
+ @port = port
13
+ end
14
+
15
+ def process_messages
16
+ logger.info "#{self.class.name} entering process_messages loop"
17
+ # trap('TERM') { puts "## Got the term signal"; @stop = true }
18
+ # trap('INT') { puts "## Got the int signal"; @stop = true }
19
+ # Set the queue that we will be watching
20
+ pool.watch(Ayl::MessageOptions.default_queue_name)
21
+ while true
22
+ break if @stop
23
+ job = pool.reserve
24
+ break if job.nil?
25
+ begin
26
+ process_message(Ayl::Message.from_hash(job.ybody))
27
+ job.delete
28
+ rescue Ayl::UnrecoverableMessageException => ex
29
+ logger.error "#{self.class.name} Unrecoverable exception in process_messages: #{ex}"
30
+ job.delete
31
+ rescue Exception => ex
32
+ logger.error "#{self.class.name} Exception in process_messages: #{ex}\n#{ex.backtrace.join("\n")}"
33
+ if job.age > 60
34
+ job.delete
35
+ else
36
+ job.decay
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+
46
+ end
@@ -0,0 +1,103 @@
1
+ require 'spec_helper'
2
+ require 'optparse'
3
+ require 'ayl-beanstalk/command_line'
4
+
5
+ describe "ayl_worker script" do
6
+
7
+ before(:each) do
8
+ ARGV.clear
9
+ @ayl_script = File.join(File.dirname(File.expand_path(__FILE__)), '../bin/ayl_worker')
10
+ end
11
+
12
+ context "handling command line" do
13
+
14
+ it "requires that an application path be specified" do
15
+ Object.any_instance.stub(:puts)
16
+ lambda { load(@ayl_script, true) }.should exit_with_code(64)
17
+ end
18
+
19
+ it "should exit with a status code of 0 if help is invoked" do
20
+ ARGV << '--help'
21
+ Ayl::CommandLine.stub(:puts)
22
+ lambda { load(@ayl_script, true) }.should exit_with_code(0)
23
+ end
24
+
25
+ it "should exit when an invalid argument is specified" do
26
+ ARGV << '--not-real'
27
+
28
+ lambda { load(@ayl_script, true) }.should raise_error(OptionParser::InvalidOption)
29
+ end
30
+
31
+ it "should set the correct tube name when specified on the command line" do
32
+ ARGV.concat [ "-a", "support", "-t", "the-tube" ]
33
+
34
+ Ayl::MessageOptions.should_receive(:default_queue_name=).with('the-tube')
35
+
36
+ mock_worker = mock("Worker")
37
+ mock_worker.should_receive(:process_messages)
38
+ mock_worker.should_receive(:eval_binding=)
39
+
40
+ mock_active_engine = mock("ActiveEngine")
41
+ mock_active_engine.should_receive(:worker).and_return(mock_worker)
42
+
43
+ Ayl::Engine.should_receive(:get_active_engine).and_return(mock_active_engine)
44
+
45
+ load(@ayl_script, true)
46
+ end
47
+
48
+ it "should set the default tube name when not specified on the command line" do
49
+ ARGV.concat [ "-a", "support" ]
50
+
51
+ Ayl::MessageOptions.should_receive(:default_queue_name=).with('default')
52
+
53
+ mock_worker = mock("Worker")
54
+ mock_worker.should_receive(:process_messages)
55
+ mock_worker.should_receive(:eval_binding=)
56
+
57
+ mock_active_engine = mock("ActiveEngine")
58
+ mock_active_engine.should_receive(:worker).and_return(mock_worker)
59
+
60
+ Ayl::Engine.should_receive(:get_active_engine).and_return(mock_active_engine)
61
+
62
+ load(@ayl_script, true)
63
+ end
64
+
65
+ it "should default to a rails production environment if not specified" do
66
+ ARGV.concat [ "-a", "support", "-r" ]
67
+
68
+ Ayl::MessageOptions.should_receive(:default_queue_name=).with('default')
69
+
70
+ mock_worker = mock("Worker")
71
+ mock_worker.should_receive(:process_messages)
72
+ mock_worker.should_receive(:eval_binding=)
73
+
74
+ mock_active_engine = mock("ActiveEngine")
75
+ mock_active_engine.should_receive(:worker).and_return(mock_worker)
76
+
77
+ Ayl::Engine.should_receive(:get_active_engine).and_return(mock_active_engine)
78
+ ENV.should_receive(:[]=).with('RAILS_ENV', 'production')
79
+
80
+ load(@ayl_script, true)
81
+ end
82
+
83
+ it "should use the specified rails environment" do
84
+ ARGV.concat [ "-a", "support", "-r", "-e", "development" ]
85
+
86
+ Ayl::MessageOptions.should_receive(:default_queue_name=).with('default')
87
+
88
+ mock_worker = mock("Worker")
89
+ mock_worker.should_receive(:process_messages)
90
+ mock_worker.should_receive(:eval_binding=)
91
+
92
+ mock_active_engine = mock("ActiveEngine")
93
+ mock_active_engine.should_receive(:worker).and_return(mock_worker)
94
+
95
+ Ayl::Engine.should_receive(:get_active_engine).and_return(mock_active_engine)
96
+ ENV.should_receive(:[]=).with('RAILS_ENV', 'development')
97
+
98
+ load(@ayl_script, true)
99
+ end
100
+
101
+ end
102
+
103
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+ require 'ayl-beanstalk/command_line'
3
+
4
+ describe Ayl::CommandLine do
5
+
6
+ context "when extracting the appropriate arguments from the command line" do
7
+
8
+ it "grab only the arguments following the application marker" do
9
+ raw_argv = %w{ start -- -a path-to-app -r -e development }
10
+
11
+ app_arguments = %w{ -a path-to-app -r -e development }
12
+
13
+ Ayl::CommandLine.grab_app_arguments(raw_argv).should == app_arguments
14
+ end
15
+
16
+ it "raise an exception if no application marker exists in the command line arguments" do
17
+ raw_argv = %w{ start -a path-to-app -r -e development }
18
+ lambda { Ayl::CommandLine.grab_app_arguments(raw_argv) }.should raise_exception
19
+ end
20
+
21
+ end
22
+
23
+ context "when parsing the command line" do
24
+
25
+ it "should extract the correct options from the command line when the short options are used" do
26
+ argv = %w{ -t tube_name -e development -a app_path -r -c config/environment -p pid_path }
27
+ parsed_options = Ayl::CommandLine.parse!(argv)
28
+ parsed_options.should == { :tube => 'tube_name', :env => 'development', :app_path => 'app_path', :rails_app => true, :app_require => 'config/environment', :pid_path => 'pid_path' }
29
+ end
30
+
31
+ it "should extract the correct options from the command line when the long options are used" do
32
+ argv = %w{ --tube tube_name --environment development --app-path app_path --rails --require config/environment --pid-path pid_path }
33
+ parsed_options = Ayl::CommandLine.parse!(argv)
34
+ parsed_options.should == { :tube => 'tube_name', :env => 'development', :app_path => 'app_path', :rails_app => true, :app_require => 'config/environment', :pid_path => 'pid_path' }
35
+ end
36
+
37
+ it "should raise an exception if invalid arguments are provided" do
38
+ argv = %w{ --tuber tube_name --environmen development --apppath app_path --rail --require config/environment --pidpath pid_path }
39
+ lambda { Ayl::CommandLine.parse!(argv) }.should raise_exception
40
+ end
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+ require 'beanstalk-client'
3
+ require 'active_record'
4
+ require 'active_record/errors'
5
+
6
+ describe Ayl::Beanstalk::Engine do
7
+
8
+ context "Standard API" do
9
+
10
+ before(:each) do
11
+ Kernel.stub(:puts)
12
+ @engine = Ayl::Beanstalk::Engine.new
13
+ @engine.stub_chain(:logger, :info)
14
+ @engine.stub_chain(:logger, :error)
15
+ end
16
+
17
+ it "should respond true to the asynchronous? message" do
18
+ @engine.asynchronous?.should be_true
19
+ end
20
+
21
+ it "should return true if it has a valid connection to beanstalk" do
22
+ mock_pool = mock("Beanstalk::Pool")
23
+
24
+ ::Beanstalk::Pool.should_receive(:new).with([ "localhost:11300" ]).and_return(mock_pool)
25
+
26
+ @engine.is_connected?.should be_true
27
+ end
28
+
29
+ it "should return false if it does not have a valid connection to beanstalk" do
30
+ ::Beanstalk::Pool.should_receive(:new).with([ "localhost:11300" ]).and_raise(::Beanstalk::NotConnected)
31
+
32
+ @engine.is_connected?.should be_false
33
+ end
34
+
35
+ context "Message Submission" do
36
+
37
+ before(:each) do
38
+ @msg = Ayl::Message.new(23, :to_s, Ayl::MessageOptions.new, 2)
39
+ end
40
+
41
+ it "should submit the specified message to beanstalk" do
42
+ mock_pool = mock("Beanstalk::Pool")
43
+ mock_pool.should_receive(:use).with("default")
44
+ mock_pool.should_receive(:yput).with( { :type => :ayl, :code => "23.to_s(2)" }, 512, 0, 120)
45
+
46
+ ::Beanstalk::Pool.should_receive(:new).with([ "localhost:11300" ]).and_return(mock_pool)
47
+
48
+ @engine.submit(@msg)
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'ayl-beanstalk'
5
+
6
+ # Requires supporting files with custom matchers and macros, etc,
7
+ # in ./support/ and its subdirectories.
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
+
10
+ RSpec.configure do |config|
11
+
12
+ end
@@ -0,0 +1,9 @@
1
+ # This is a fake Rails application environment.
2
+ # DON'T delete
3
+ module Ayl
4
+
5
+ module Environment
6
+
7
+ end
8
+
9
+ end
@@ -0,0 +1,24 @@
1
+ module ExitCodeMatchers
2
+
3
+ RSpec::Matchers.define :exit_with_code do | code |
4
+ actual = nil
5
+ match do |block|
6
+ begin
7
+ block.call
8
+ rescue SystemExit => ex
9
+ actual = ex.status
10
+ end
11
+ actual and actual == code
12
+ end
13
+
14
+ failure_message_for_should do |block|
15
+ "expected block to call exit(#{code}) but exit" + (actual.nil? ? " not called" : "(#{actual}) was called")
16
+ end
17
+ failure_message_for_should_not do |block|
18
+ "expected block not to call exit(#{code})"
19
+ end
20
+ description do
21
+ "expect block to call exit(#{code})"
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,130 @@
1
+ require 'spec_helper'
2
+ require 'beanstalk-client'
3
+ require 'active_record'
4
+ require 'active_record/errors'
5
+
6
+ describe Ayl::Beanstalk::Worker do
7
+
8
+ context "Message Processing" do
9
+
10
+ before(:each) do
11
+ Kernel.stub(:puts)
12
+ @worker = Ayl::Beanstalk::Worker.new
13
+ @worker.stub_chain(:logger, :info)
14
+ @worker.stub_chain(:logger, :error)
15
+ end
16
+
17
+ it "should wait for a message to be received from beanstalk and process it" do
18
+ mock_job = mock("Beanstalk::Job")
19
+ mock_job.should_receive(:delete)
20
+ mock_job.should_receive(:ybody).and_return({ :type => :ayl, :code => "23.to_s(2)" })
21
+
22
+ mock_pool = mock("Beanstalk::Pool")
23
+ mock_pool.should_receive(:watch).with("default")
24
+ # Returns nil on the second call.
25
+ mock_pool.should_receive(:reserve).and_return(mock_job, nil)
26
+
27
+ mock_message = mock("Ayl::Message")
28
+ mock_message.should_receive(:evaluate)
29
+ Ayl::Message.stub(:from_hash).with({ :type => :ayl, :code => "23.to_s(2)" }).and_return(mock_message)
30
+
31
+ ::Beanstalk::Pool.should_receive(:new).with([ "localhost:11300" ]).and_return(mock_pool)
32
+
33
+ @worker.process_messages
34
+
35
+ end
36
+
37
+ it "should raise an UnrecoverableMessageException when the message body is not a valid hash" do
38
+ mock_job = mock("Beanstalk::Job")
39
+ mock_job.should_receive(:delete)
40
+ mock_job.should_receive(:ybody).and_return("a string")
41
+ mock_job.should_not_receive(:age)
42
+
43
+ mock_pool = mock("Beanstalk::Pool")
44
+ mock_pool.should_receive(:watch).with("default")
45
+ # Returns nil on the second call.
46
+ mock_pool.should_receive(:reserve).and_return(mock_job, nil)
47
+
48
+ Ayl::Message.stub(:from_hash).with("a string").and_raise(Ayl::UnrecoverableMessageException)
49
+
50
+ ::Beanstalk::Pool.should_receive(:new).with([ "localhost:11300" ]).and_return(mock_pool)
51
+
52
+ @worker.process_messages
53
+ end
54
+
55
+ it "should raise an UnrecoverableJobException when the message body is not a valid job type" do
56
+ mock_job = mock("Beanstalk::Job")
57
+ mock_job.should_receive(:delete)
58
+ mock_job.should_receive(:ybody).and_return({ :type => :junk, :code => "Dog" })
59
+ mock_job.should_not_receive(:age)
60
+
61
+ mock_pool = mock("Beanstalk::Pool")
62
+ mock_pool.should_receive(:watch).with("default")
63
+ # Returns nil on the second call.
64
+ mock_pool.should_receive(:reserve).and_return(mock_job, nil)
65
+
66
+ Ayl::Message.stub(:from_hash).with({ :type => :junk, :code => "Dog" }).and_raise(Ayl::UnrecoverableMessageException)
67
+
68
+ ::Beanstalk::Pool.should_receive(:new).with([ "localhost:11300" ]).and_return(mock_pool)
69
+
70
+ @worker.process_messages
71
+ end
72
+
73
+ it "should raise an UnrecoverableJobException when there is no code in the message body" do
74
+ mock_job = mock("Beanstalk::Job")
75
+ mock_job.should_receive(:delete)
76
+ mock_job.should_receive(:ybody).and_return({ :type => :ayl })
77
+ mock_job.should_not_receive(:age)
78
+
79
+ mock_pool = mock("Beanstalk::Pool")
80
+ mock_pool.should_receive(:watch).with("default")
81
+ # Returns nil on the second call.
82
+ mock_pool.should_receive(:reserve).and_return(mock_job, nil)
83
+
84
+ Ayl::Message.stub(:from_hash).with({ :type => :ayl }).and_raise(Ayl::UnrecoverableMessageException)
85
+
86
+ ::Beanstalk::Pool.should_receive(:new).with([ "localhost:11300" ]).and_return(mock_pool)
87
+
88
+ @worker.process_messages
89
+ end
90
+
91
+ it "should decay a job that receives an active-record exception on receipt of message that is less than 60 seconds old" do
92
+ mock_job = mock("Beanstalk::Job")
93
+ mock_job.should_receive(:decay)
94
+ mock_job.should_receive(:ybody).and_return({ :type => :ayl, :code => "Dog" })
95
+ mock_job.should_receive(:age).and_return(10)
96
+
97
+ mock_pool = mock("Beanstalk::Pool")
98
+ mock_pool.should_receive(:watch).with("default")
99
+ mock_pool.should_receive(:reserve).and_return(mock_job, nil)
100
+
101
+ mock_message = mock("Ayl::Message")
102
+ mock_message.should_receive(:evaluate).and_raise(ActiveRecord::RecordNotFound)
103
+ Ayl::Message.stub(:from_hash).with({ :type => :ayl, :code => "Dog" }).and_return(mock_message)
104
+
105
+ ::Beanstalk::Pool.should_receive(:new).with([ "localhost:11300" ]).and_return(mock_pool)
106
+
107
+ @worker.process_messages
108
+ end
109
+
110
+ it "should delete a job that receives an active-record exception on receipt of message that is more than 60 seconds old" do
111
+ mock_job = mock("Beanstalk::Job")
112
+ mock_job.should_receive(:delete)
113
+ mock_job.should_receive(:ybody).and_return({ :type => :ayl, :code => "Dog" })
114
+ mock_job.should_receive(:age).and_return(65)
115
+
116
+ mock_pool = mock("Beanstalk::Pool")
117
+ mock_pool.should_receive(:watch).with("default")
118
+ mock_pool.should_receive(:reserve).and_return(mock_job, nil)
119
+
120
+ mock_message = mock("Ayl::Message")
121
+ mock_message.should_receive(:evaluate).and_raise(ActiveRecord::RecordNotFound)
122
+ Ayl::Message.stub(:from_hash).with({ :type => :ayl, :code => "Dog" }).and_return(mock_message)
123
+
124
+ ::Beanstalk::Pool.should_receive(:new).with([ "localhost:11300" ]).and_return(mock_pool)
125
+
126
+ @worker.process_messages
127
+ end
128
+ end
129
+
130
+ end
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ayl-beanstalk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - j0hnds@gmail.com
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-11-20 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: ayl
16
+ requirement: &87968020 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.1.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *87968020
25
+ - !ruby/object:Gem::Dependency
26
+ name: beanstalk-client
27
+ requirement: &87967750 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 1.1.0
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *87967750
36
+ - !ruby/object:Gem::Dependency
37
+ name: daemons
38
+ requirement: &87967500 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: 1.1.0
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *87967500
47
+ - !ruby/object:Gem::Dependency
48
+ name: rspec
49
+ requirement: &87967220 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 2.3.0
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *87967220
58
+ - !ruby/object:Gem::Dependency
59
+ name: bundler
60
+ requirement: &87966960 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: 1.0.0
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *87966960
69
+ - !ruby/object:Gem::Dependency
70
+ name: jeweler
71
+ requirement: &87966690 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: 1.6.4
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *87966690
80
+ - !ruby/object:Gem::Dependency
81
+ name: rcov
82
+ requirement: &87966350 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *87966350
91
+ - !ruby/object:Gem::Dependency
92
+ name: pry
93
+ requirement: &87966010 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ type: :development
100
+ prerelease: false
101
+ version_requirements: *87966010
102
+ description: Ayl extension to provide beanstalk support.
103
+ email: j0hnds@gmail.com
104
+ executables:
105
+ - ayl_beanstalk
106
+ - ayl_worker
107
+ - ayl_worker_control
108
+ extensions: []
109
+ extra_rdoc_files:
110
+ - LICENSE.txt
111
+ - README.rdoc
112
+ files:
113
+ - .document
114
+ - .rspec
115
+ - Gemfile
116
+ - Gemfile.lock
117
+ - LICENSE.txt
118
+ - README.rdoc
119
+ - Rakefile
120
+ - VERSION
121
+ - bin/ayl_beanstalk
122
+ - bin/ayl_worker
123
+ - bin/ayl_worker_control
124
+ - lib/ayl-beanstalk.rb
125
+ - lib/ayl-beanstalk/command_line.rb
126
+ - lib/ayl-beanstalk/engine.rb
127
+ - lib/ayl-beanstalk/pool.rb
128
+ - lib/ayl-beanstalk/worker.rb
129
+ - spec/ayl_worker_spec.rb
130
+ - spec/command_line_spec.rb
131
+ - spec/engine_spec.rb
132
+ - spec/spec_helper.rb
133
+ - spec/support/config/environment.rb
134
+ - spec/support/exit_code_matchers.rb
135
+ - spec/worker_spec.rb
136
+ homepage: http://github.com/j0hnds/ayl-beanstalk
137
+ licenses:
138
+ - MIT
139
+ post_install_message:
140
+ rdoc_options: []
141
+ require_paths:
142
+ - lib
143
+ required_ruby_version: !ruby/object:Gem::Requirement
144
+ none: false
145
+ requirements:
146
+ - - ! '>='
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ segments:
150
+ - 0
151
+ hash: 349899887
152
+ required_rubygems_version: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ requirements: []
159
+ rubyforge_project:
160
+ rubygems_version: 1.8.10
161
+ signing_key:
162
+ specification_version: 3
163
+ summary: Ayl extension to provide beanstalk support.
164
+ test_files: []