newbamboo-job_queue 0.0.5

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.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Martyn Loughran
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.markdown ADDED
@@ -0,0 +1,58 @@
1
+ JobQueue
2
+ ========
3
+
4
+ `job_queue` allows you to use lots of message queues with exactly the same interface so you don't need to worry about which queue to pick :)
5
+
6
+ This should get you started:
7
+
8
+ require 'rubygems'
9
+ require 'job_queue'
10
+
11
+ Before you can do anything you must specify an adapter to use
12
+
13
+ JobQueue.adapter = JobQueue::BeanstalkAdapter.new
14
+
15
+ Jobs can then be simply added to the queue
16
+
17
+ JobQueue.put("flubble bubble")
18
+
19
+ In your workers you'll want to subscribe to a queue
20
+
21
+ JobQueue.subscribe do |job|
22
+ puts job
23
+ end
24
+
25
+ This subscribe block takes care of waiting for the next job to arrive and the block is passed exactly what you passed in. If you want to exit the loop just throw :stop.
26
+
27
+ JobQueue.subscribe do |job|
28
+ # Wait - I changed my mind!
29
+ throw :stop
30
+ end
31
+
32
+ What should you put on the queue
33
+ --------------------------------
34
+
35
+ You might love Ruby right now, but why lock yourself in? Often the kinds of things you use queues for are the kind of things you'll want to optimize. This is a good place to start:
36
+
37
+ JSON.generate({:some => "hash"})
38
+ JSON.parse(job)
39
+
40
+ Can you show me a nice processing daemon?
41
+ -----------------------------------------
42
+
43
+ Yes. Just a minute...
44
+
45
+ Adapters
46
+ ========
47
+
48
+ Take your pick! Right now we have:
49
+
50
+ Beanstalk
51
+ ---------
52
+ <http://xph.us/software/beanstalkd/>
53
+
54
+ AMQP
55
+ ----
56
+ <http://github.com/tmm1/amqp/>
57
+
58
+ You need to run all your code within an eventmachine loop to use AMQP.
data/Rakefile ADDED
@@ -0,0 +1,38 @@
1
+ require 'rake'
2
+
3
+ begin
4
+ require 'jeweler'
5
+ Jeweler::Tasks.new do |s|
6
+ s.name = "job_queue"
7
+ s.summary = %Q{JobQueue means you don't have to worry about your queue any more!}
8
+ s.email = "me@mloughran.com"
9
+ s.homepage = "http://github.com/mloughran/job_queue"
10
+ s.description = "JobQueue means you don't have to worry about your queue any more!"
11
+ s.authors = ["Martyn Loughran"]
12
+ end
13
+ rescue LoadError
14
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
15
+ end
16
+
17
+ require 'rake/rdoctask'
18
+ Rake::RDocTask.new do |rdoc|
19
+ rdoc.rdoc_dir = 'rdoc'
20
+ rdoc.title = 'job_queue'
21
+ rdoc.options << '--line-numbers' << '--inline-source'
22
+ rdoc.rdoc_files.include('README*')
23
+ rdoc.rdoc_files.include('lib/**/*.rb')
24
+ end
25
+
26
+ require 'spec/rake/spectask'
27
+ Spec::Rake::SpecTask.new(:spec) do |t|
28
+ t.libs << 'lib' << 'spec'
29
+ t.spec_files = FileList['spec/**/*_spec.rb']
30
+ end
31
+
32
+ Spec::Rake::SpecTask.new(:rcov) do |t|
33
+ t.libs << 'lib' << 'spec'
34
+ t.spec_files = FileList['spec/**/*_spec.rb']
35
+ t.rcov = true
36
+ end
37
+
38
+ task :default => :spec
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :patch: 4
3
+ :major: 0
4
+ :minor: 0
@@ -0,0 +1,28 @@
1
+ require 'mq'
2
+
3
+ class JobQueue::AMQPAdapter
4
+ def initialize(options = {})
5
+ amq = MQ.new
6
+ @exchange = amq.direct('photo', :durable => true)
7
+ @queue = amq.queue('photo_worker', :durable => true)
8
+ @queue.bind(@exchange)
9
+ end
10
+
11
+ def put(string)
12
+ @queue.publish(string, :persistent => true)
13
+ end
14
+
15
+ def subscribe(error_report, &block)
16
+ EM.add_periodic_timer(0) do
17
+ begin
18
+ @queue.pop do |header, body|
19
+ next unless body
20
+ JobQueue.logger.info "AMQP received #{body}"
21
+ yield body
22
+ end
23
+ rescue => e
24
+ error_report.call(job.body, e)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ require 'beanstalk-client'
2
+
3
+ class JobQueue::BeanstalkAdapter
4
+ def initialize(options = {})
5
+ host = options[:host] || 'localhost'
6
+ port = options[:port] || 11300
7
+ @beanstalk = Beanstalk::Pool.new(["#{host}:#{port}"])
8
+ end
9
+
10
+ def put(string)
11
+ @beanstalk.put(string)
12
+ end
13
+
14
+ def subscribe(error_report, &block)
15
+ loop do
16
+ begin
17
+ job = @beanstalk.reserve
18
+ JobQueue.logger.info "Beanstalk received #{job.body}"
19
+ yield job.body
20
+ job.delete
21
+ rescue Beanstalk::DeadlineSoonError => e
22
+ error_report.call(job, e)
23
+ rescue => e
24
+ error_report.call(job.body, e)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,20 @@
1
+ class JobQueue::TestAdapter
2
+ def initialize(options = {})
3
+ @queue = []
4
+ end
5
+
6
+ def put(string)
7
+ @queue << string
8
+ end
9
+
10
+ def subscribe(error_report, &block)
11
+ loop do
12
+ begin
13
+ sleep 0.1 if @queue.empty?
14
+ yield @queue.shift
15
+ rescue
16
+ error_report.call(job.body, e)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ # This isn't a queue at all, it just writes to standard output.
2
+ #
3
+ # It might be useful for testing.
4
+ #
5
+ class JobQueue::VerboseAdapter
6
+ def initialize(options = {})
7
+
8
+ end
9
+
10
+ def put(string)
11
+ JobQueue.logger.debug "===== NEW JOB ADDED TO QUEUE ===="
12
+ JobQueue.logger.debug string
13
+ JobQueue.logger.debug "===== END OF MESSAGE ============"
14
+ end
15
+
16
+ def subscribe(error_report, &block)
17
+ raise "Not implemented. Use a better adapter!!"
18
+ end
19
+ end
@@ -0,0 +1,52 @@
1
+ # JobQueue abstracts the task of adding work to a queue.
2
+ #
3
+ # Beanstalk is fantastic, but maybe not "enterprise grade".
4
+ #
5
+ # AMQP is fantastic, but it's bloody complex and has to run inside an
6
+ # eventmachine loop.
7
+ #
8
+ # Take your pick!
9
+ #
10
+ # Before use, an adapter must be chosen:
11
+ #
12
+ # JobQueue.adapter = JobQueue::BeanstalkAdapter.new
13
+ #
14
+ # Jobs can then be simply added to the queue with
15
+ #
16
+ # JobQueue.put("flubble bubble")
17
+ #
18
+ class JobQueue
19
+ class << self
20
+ attr_accessor :adapter
21
+ attr_accessor :logger
22
+
23
+ def logger
24
+ @logger ||= begin
25
+ logger = Logger.new(STDOUT)
26
+ logger.level = Logger::WARN
27
+ logger.debug("Created logger")
28
+ logger
29
+ end
30
+ end
31
+ end
32
+
33
+ def self.put(string)
34
+ adapter.put(string)
35
+ end
36
+
37
+ def self.subscribe(error_report = nil, &block)
38
+ catch :stop do
39
+ error_report ||= Proc.new do |job, e|
40
+ JobQueue.logger.error \
41
+ "Job failed\n" \
42
+ "==========\n" \
43
+ "Job content: #{job.inspect}\n" \
44
+ "Exception: #{e.message}\n" \
45
+ "#{e.backtrace.join("\n")}\n" \
46
+ "\n"
47
+ end
48
+
49
+ adapter.subscribe(error_report, &block)
50
+ end
51
+ end
52
+ end
data/lib/job_queue.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'logger'
2
+ require 'job_queue/job_queue'
3
+
4
+ JobQueue.autoload 'AMQPAdapter', 'job_queue/adapters/amqp_adapter'
5
+ JobQueue.autoload 'BeanstalkAdapter', 'job_queue/adapters/beanstalk_adapter'
6
+ JobQueue.autoload 'TestAdapter', 'job_queue/adapters/test_adapter'
7
+ JobQueue.autoload 'VerboseAdapter', 'job_queue/adapters/verbose_adapter'
@@ -0,0 +1,8 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe JobQueue::AMQPAdapter do
4
+
5
+ it "should write onto queue and fetch stuff back off" do
6
+ pending "need to figure out a nice way of running rspec inside EM block"
7
+ end
8
+ end
@@ -0,0 +1,60 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe JobQueue::BeanstalkAdapter do
4
+ before :all do
5
+ JobQueue.adapter = JobQueue::BeanstalkAdapter.new
6
+ end
7
+
8
+ describe '#new' do
9
+ it "should default to localhost:11300" do
10
+ Beanstalk::Pool.should_receive(:new).with(['localhost:11300'])
11
+ JobQueue::BeanstalkAdapter.new
12
+ end
13
+
14
+ it "should use options provided" do
15
+ Beanstalk::Pool.should_receive(:new).with(['12.34.56.78:12345'])
16
+ JobQueue::BeanstalkAdapter.new(:host => '12.34.56.78', :port => 12345)
17
+ end
18
+ end
19
+
20
+ it "should write onto queue and fetch stuff back off" do
21
+ JobQueue.put("hello")
22
+
23
+ JobQueue.subscribe do |job|
24
+ @job = job
25
+ throw :stop
26
+ end
27
+
28
+ @job.should == "hello"
29
+ end
30
+
31
+ it "should output message if error raised in job" do
32
+ JobQueue.put("hello")
33
+
34
+ JobQueue.logger.should_receive(:error).with(/Job failed\w*/)
35
+
36
+ index = 0
37
+ JobQueue.subscribe do |job|
38
+ index +=1
39
+ raise 'foo' if index == 1
40
+ throw :stop
41
+ end
42
+ end
43
+
44
+ it "should use error_report block if supplied" do
45
+ JobQueue.put("hello")
46
+
47
+ error_report = Proc.new do |job, e|
48
+ JobQueue.logger.error "Yikes that broke matey!"
49
+ end
50
+
51
+ JobQueue.logger.should_receive(:error).with("Yikes that broke matey!")
52
+
53
+ index = 0
54
+ JobQueue.subscribe(error_report) do |job|
55
+ index +=1
56
+ raise 'foo' if index == 1
57
+ throw :stop
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,5 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe JobQueue do
4
+
5
+ end
@@ -0,0 +1,5 @@
1
+ $TESTING=true
2
+ $:.push File.join(File.dirname(__FILE__), '..', 'lib')
3
+
4
+ require 'rubygems'
5
+ require 'job_queue'
@@ -0,0 +1,39 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe JobQueue::TestAdapter do
4
+ before :all do
5
+ JobQueue.adapter = JobQueue::TestAdapter.new
6
+ end
7
+
8
+ it "should write onto queue and fetch stuff back off" do
9
+ JobQueue.put("hello")
10
+
11
+ JobQueue.subscribe do |job|
12
+ @job = job
13
+ throw :stop
14
+ end
15
+
16
+ @job.should == "hello"
17
+ end
18
+
19
+ it "should pull items off in the order the were added" do
20
+ JobQueue.put("foo")
21
+ JobQueue.put("bar")
22
+
23
+ retrieved_jobs = []
24
+
25
+ begin
26
+ Timeout::timeout(0.5) do
27
+ JobQueue.subscribe do |job|
28
+ retrieved_jobs << job
29
+ end
30
+ end
31
+ rescue Timeout::Error
32
+
33
+ end
34
+
35
+ retrieved_jobs[0].should == "foo"
36
+ retrieved_jobs[1].should == "bar"
37
+ retrieved_jobs[2].should == nil
38
+ end
39
+ end
@@ -0,0 +1,15 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe JobQueue::VerboseAdapter do
4
+ before :all do
5
+ JobQueue.adapter = JobQueue::VerboseAdapter.new
6
+ end
7
+
8
+ it "should write onto queue and output a very verbose message to stdout" do
9
+ JobQueue.logger.should_receive(:debug).with("===== NEW JOB ADDED TO QUEUE ====")
10
+ JobQueue.logger.should_receive(:debug).with("hello")
11
+ JobQueue.logger.should_receive(:debug).with("===== END OF MESSAGE ============")
12
+
13
+ JobQueue.put("hello")
14
+ end
15
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: newbamboo-job_queue
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.5
5
+ platform: ruby
6
+ authors:
7
+ - Martyn Loughran
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-04-16 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: JobQueue means you don't have to worry about your queue any more!
17
+ email: me@mloughran.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - LICENSE
24
+ - README.markdown
25
+ files:
26
+ - LICENSE
27
+ - README.markdown
28
+ - Rakefile
29
+ - VERSION.yml
30
+ - lib/job_queue.rb
31
+ - lib/job_queue/adapters/amqp_adapter.rb
32
+ - lib/job_queue/adapters/beanstalk_adapter.rb
33
+ - lib/job_queue/adapters/test_adapter.rb
34
+ - lib/job_queue/adapters/verbose_adapter.rb
35
+ - lib/job_queue/job_queue.rb
36
+ - spec/amqp_adapter_spec.rb
37
+ - spec/beanstalk_adapter_spec.rb
38
+ - spec/job_queue_spec.rb
39
+ - spec/spec_helper.rb
40
+ - spec/test_adapter_spec.rb
41
+ - spec/verbose_adapter_spec.rb
42
+ has_rdoc: true
43
+ homepage: http://github.com/mloughran/job_queue
44
+ post_install_message:
45
+ rdoc_options:
46
+ - --charset=UTF-8
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ requirements: []
62
+
63
+ rubyforge_project:
64
+ rubygems_version: 1.2.0
65
+ signing_key:
66
+ specification_version: 2
67
+ summary: JobQueue means you don't have to worry about your queue any more!
68
+ test_files:
69
+ - spec/amqp_adapter_spec.rb
70
+ - spec/beanstalk_adapter_spec.rb
71
+ - spec/job_queue_spec.rb
72
+ - spec/spec_helper.rb
73
+ - spec/test_adapter_spec.rb
74
+ - spec/verbose_adapter_spec.rb