quebert 1.0.9 → 1.11.0

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/Gemfile CHANGED
@@ -14,5 +14,4 @@ group :test do
14
14
  gem 'sqlite3-ruby'
15
15
  gem 'guard-rspec'
16
16
  gem 'rb-fsevent'
17
- gem 'growl'
18
17
  end
data/Guardfile CHANGED
@@ -1,7 +1,4 @@
1
- # A sample Guardfile
2
- # More info at https://github.com/guard/guard#readme
3
-
4
- guard 'rspec', :version => 1, :cli => '--colour --format nested' do
1
+ guard 'rspec', :version => 2, :cli => '--colour --format nested' do
5
2
  watch(%r{^spec/.+_spec\.rb$})
6
3
  watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
4
  watch('spec/spec_helper.rb') { "spec" }
@@ -1,36 +1,48 @@
1
- require 'beanstalk-client'
1
+ require 'beaneater'
2
2
 
3
3
  module Quebert
4
4
  module Backend
5
5
 
6
6
  # Manage jobs on a Beanstalk queue out of process
7
- class Beanstalk < Beanstalk::Pool
7
+ class Beanstalk
8
8
  def put(job, *args)
9
- super job.to_json, *args
9
+ priority, delay, ttr = args
10
+ opts = {}
11
+ opts[:pri] = priority unless priority.nil?
12
+ opts[:delay] = delay unless delay.nil?
13
+ opts[:ttr] = ttr unless ttr.nil?
14
+ @tube.put job.to_json, opts
10
15
  end
11
-
12
- def reserve_with_controller
13
- Controller::Beanstalk.new(reserve_without_controller, self)
16
+
17
+ def reserve_without_controller(timeout=nil)
18
+ @tube.reserve timeout
14
19
  end
15
- alias :reserve_without_controller :reserve
16
- alias :reserve :reserve_with_controller
17
-
20
+
21
+ def reserve(timeout=nil)
22
+ Controller::Beanstalk.new reserve_without_controller(timeout), self
23
+ end
24
+
25
+ def peek(state)
26
+ @tube.peek state
27
+ end
28
+
18
29
  # For testing purposes... I think there's a better way to do this though.
19
30
  def drain!
20
- while peek_ready do
31
+ while peek(:ready) do
21
32
  reserve_without_controller.delete
22
33
  end
23
- while peek_delayed do
34
+ while peek(:delayed) do
24
35
  reserve_without_controller.delete
25
36
  end
26
- while job = peek_buried do
27
- last_conn.kick 1 # what? Why the 1? it kicks them all?
37
+ while peek(:buried) do
38
+ @tube.kick
28
39
  reserve_without_controller.delete
29
40
  end
30
41
  end
31
42
 
32
- def initialize(host, *args)
33
- super Array(host), *args
43
+ def initialize(host, tube)
44
+ @pool = Beaneater::Pool.new Array(host)
45
+ @tube = @pool.tubes[tube]
34
46
  end
35
47
  def self.configure(opts={})
36
48
  opts[:host] ||= ['127.0.0.1:11300']
@@ -1,45 +1,47 @@
1
+ require 'optparse'
2
+
1
3
  module Quebert
2
4
  class CommandLineRunner
3
-
5
+
4
6
  attr_accessor :arguments, :command, :options
5
-
7
+
6
8
  def initialize(argv)
7
9
  @argv = argv
8
-
10
+
9
11
  # Default options values
10
12
  @options = {
11
13
  :chdir => Dir.pwd
12
14
  }
13
-
15
+
14
16
  parse!
15
17
  end
16
-
18
+
17
19
  def parser
18
20
  @parser ||= OptionParser.new do |opts|
19
21
  opts.banner = "Usage: quebert [options]"
20
-
22
+
21
23
  opts.separator ""
22
-
23
- opts.on("-l", "--log FILE", "File to redirect output " +
24
+
25
+ opts.on("-l", "--log FILE", "File to redirect output " +
24
26
  "(default: #{@options[:log]})") { |file| @options[:log] = file }
25
- opts.on("-P", "--pid FILE", "File to store PID " +
27
+ opts.on("-P", "--pid FILE", "File to store PID " +
26
28
  "(default: #{@options[:pid]})") { |file| @options[:pid] = file }
27
29
  opts.on("-C", "--config FILE", "Load options from config file") { |file| @options[:config] = file }
28
30
  opts.on("-c", "--chdir DIR", "Change to dir before starting") { |dir| @options[:chdir] = File.expand_path(dir) }
29
31
  end
30
32
  end
31
-
33
+
32
34
  # Parse the options.
33
35
  def parse!
34
36
  parser.parse! @argv
35
37
  @command = @argv.shift
36
38
  @arguments = @argv
37
39
  end
38
-
40
+
39
41
  def self.dispatch(args = ARGV)
40
42
  runner = new(args)
41
43
  params = runner.options
42
-
44
+
43
45
  if dir = params[:chdir]
44
46
  Dir.chdir dir
45
47
  end
@@ -55,10 +57,10 @@ module Quebert
55
57
  if config = params[:config] || auto_config
56
58
  require config
57
59
  end
58
-
60
+
59
61
  Worker.new.start
60
62
  end
61
-
63
+
62
64
  private
63
65
  def self.auto_config
64
66
  rails_env_path = './config/environment.rb'
@@ -52,7 +52,7 @@ module Quebert
52
52
  log "Job deleted", :error
53
53
  rescue Job::Release
54
54
  log "Releasing with priority: #{@job.priority} and delay: #{@job.delay}", :error
55
- beanstalk_job.release @job.priority, @job.delay
55
+ beanstalk_job.release :pri => @job.priority, :delay => @job.delay
56
56
  log "Job released", :error
57
57
  rescue Job::Bury
58
58
  log "Burrying job", :error
@@ -86,10 +86,10 @@ module Quebert
86
86
  log "Job burried"
87
87
  else
88
88
  log "TTR exceeded. Releasing with priority: #{@job.priority} and delay: #{delay}"
89
- beanstalk_job.release @job.priority, delay
89
+ beanstalk_job.release :pri => @job.priority, :delay => delay
90
90
  log "Job released"
91
91
  end
92
- rescue ::Beanstalk::NotFoundError => e
92
+ rescue ::Beaneater::NotFoundError => e
93
93
  log "Job ran longer than allowed. Beanstalk already deleted it!!!!", :error
94
94
  # Sometimes the timer doesn't behave correctly and this job actually runs longer than
95
95
  # allowed. At that point the beanstalk job no longer exists anymore. Lets let it go and don't blow up.
data/lib/quebert/job.rb CHANGED
@@ -6,20 +6,20 @@ module Quebert
6
6
 
7
7
  attr_reader :args
8
8
  attr_accessor :priority, :delay, :ttr
9
-
9
+
10
10
  DEFAULT_JOB_PRIORITY = 65536
11
11
  DEFAULT_JOB_DELAY = 0
12
12
  DEFAULT_JOB_TTR = 10
13
13
 
14
- # A buffer time in seconds added to the Beanstalk TTR for Quebert to do its own job cleanup
14
+ # A buffer time in seconds added to the Beanstalk TTR for Quebert to do its own job cleanup
15
15
  # The job will perform based on the Beanstalk TTR, but Beanstalk hangs on to the job just a
16
16
  # little longer so that Quebert can bury the job or schedule a retry with the appropriate delay
17
17
  QUEBERT_TTR_BUFFER = 5
18
18
 
19
19
  NotImplemented = Class.new(StandardError)
20
-
20
+
21
21
  Action = Class.new(Exception)
22
-
22
+
23
23
  Bury = Class.new(Action)
24
24
  Delete = Class.new(Action)
25
25
  Release = Class.new(Action)
@@ -28,7 +28,7 @@ module Quebert
28
28
 
29
29
  def initialize(*args)
30
30
  opts = args.last.is_a?(::Hash) ? args.pop : nil
31
-
31
+
32
32
  @priority = DEFAULT_JOB_PRIORITY
33
33
  @delay = DEFAULT_JOB_DELAY
34
34
  @ttr = DEFAULT_JOB_TTR
@@ -36,7 +36,7 @@ module Quebert
36
36
  if opts
37
37
  beanstalk_opts = opts.delete(:beanstalk)
38
38
  args << opts unless opts.empty?
39
-
39
+
40
40
  if beanstalk_opts
41
41
  @priority = beanstalk_opts[:priority] if beanstalk_opts[:priority]
42
42
  @delay = beanstalk_opts[:delay] if beanstalk_opts[:delay]
@@ -46,41 +46,37 @@ module Quebert
46
46
 
47
47
  @args = args.dup.freeze
48
48
  end
49
-
49
+
50
50
  def perform(*args)
51
51
  raise NotImplemented
52
52
  end
53
-
53
+
54
54
  # Runs the perform method that somebody else should be implementing
55
55
  def perform!
56
56
  # Honor the timeout and kill the job in ruby-space. Beanstalk
57
57
  # should be cleaning up this job and returning it to the queue
58
58
  # as well.
59
- begin
60
- Quebert::Timeout.timeout(@ttr){ perform(*args) }
61
- rescue ::Timeout::Error => e
62
- raise Job::Timeout, e.message, e.backtrace
63
- end
59
+ Quebert::Timeout.timeout(@ttr, Job::Timeout){ perform(*args) }
64
60
  end
65
-
61
+
66
62
  def enqueue
67
63
  self.class.backend.put self, @priority, @delay, @ttr + QUEBERT_TTR_BUFFER
68
64
  end
69
-
65
+
70
66
  def to_json
71
67
  JSON.generate(Serializer::Job.serialize(self))
72
68
  end
73
-
69
+
74
70
  def self.from_json(json)
75
71
  if hash = JSON.parse(json) and not hash.empty?
76
72
  Serializer::Job.deserialize(hash)
77
73
  end
78
74
  end
79
-
75
+
80
76
  def self.backend=(backend)
81
77
  @backend = backend
82
78
  end
83
-
79
+
84
80
  def self.backend
85
81
  @backend || Quebert.configuration.backend
86
82
  end
@@ -89,13 +85,13 @@ module Quebert
89
85
  def delete!
90
86
  raise Delete
91
87
  end
92
-
88
+
93
89
  def release!
94
90
  raise Release
95
91
  end
96
-
92
+
97
93
  def bury!
98
94
  raise Bury
99
95
  end
100
96
  end
101
- end
97
+ end
@@ -1,3 +1,3 @@
1
1
  module Quebert
2
- VERSION = "1.0.9"
3
- end
2
+ VERSION = "1.11.0"
3
+ end
@@ -3,29 +3,38 @@ module Quebert
3
3
  include Logging
4
4
 
5
5
  attr_accessor :exception_handler, :backend
6
-
6
+
7
7
  def initialize
8
8
  yield self if block_given?
9
9
  end
10
-
10
+
11
11
  # Start the worker backend and intercept exceptions if a handler is provided
12
12
  def start
13
13
  Signal.trap('TERM') { safe_stop }
14
14
  Signal.trap('INT') { safe_stop }
15
15
 
16
16
  logger.info "Worker started with #{backend.class.name} backend\n"
17
- while @controller = backend.reserve do
17
+ while @controller = backend.reserve do
18
18
  begin
19
19
  @controller.perform
20
- rescue Exception => e
21
- exception_handler ? exception_handler.call(e) : raise(e)
22
- end
20
+ rescue Exception => error
21
+ if exception_handler
22
+ exception_handler.call(
23
+ error,
24
+ :controller => @controller,
25
+ :pid => $$,
26
+ :worker => self
27
+ )
28
+ else
29
+ raise error
30
+ end
31
+ end
23
32
  @controller = nil
24
33
 
25
34
  stop if @terminate_sent
26
35
  end
27
36
  end
28
-
37
+
29
38
  def safe_stop
30
39
  if @terminate_sent
31
40
  logger.info "Ok! I get the point. Shutting down immediately."
@@ -41,14 +50,14 @@ module Quebert
41
50
  logger.info "Worker stopping\n"
42
51
  exit 0
43
52
  end
44
-
53
+
45
54
  protected
46
55
  def backend
47
56
  @backend ||= Quebert.config.backend
48
57
  end
49
-
58
+
50
59
  def exception_handler
51
60
  @exception_handler ||= Quebert.config.worker.exception_handler
52
61
  end
53
62
  end
54
- end
63
+ end
data/quebert.gemspec CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
21
21
  # specify any dependencies here; for example:
22
22
  # s.add_development_dependency "rspec"
23
23
  s.add_runtime_dependency "json"
24
- s.add_runtime_dependency "beanstalk-client"
24
+ s.add_runtime_dependency "beaneater"
25
25
 
26
26
  s.add_development_dependency 'rspec', '2.7.0'
27
27
  end
@@ -10,8 +10,10 @@ describe Configuration do
10
10
  backend = @config.backend
11
11
  backend.should be_instance_of(Quebert::Backend::Beanstalk)
12
12
  # Blech, gross nastiness in their lib, but we need to look in to see if this stuff as configed
13
- backend.instance_variable_get('@addrs').should eql(['localhost:11300'])
14
- backend.instance_variable_get('@default_tube').should eql('quebert-config-test')
13
+ pool = backend.instance_variable_get('@pool')
14
+ pool.connections.first.address.should eql('localhost:11300')
15
+ tube = backend.instance_variable_get('@tube')
16
+ tube.name.should eql('quebert-config-test')
15
17
  end
16
18
 
17
19
  end
@@ -25,63 +25,63 @@ describe Controller::Beanstalk do
25
25
 
26
26
  it "should delete job off queue after succesful run" do
27
27
  @q.put Adder.new(1, 2)
28
- @q.peek_ready.should_not be_nil
28
+ @q.peek(:ready).should_not be_nil
29
29
  @q.reserve.perform.should eql(3)
30
- @q.peek_ready.should be_nil
30
+ @q.peek(:ready).should be_nil
31
31
  end
32
32
 
33
33
  it "should bury job if an exception occurs in job" do
34
34
  @q.put Exceptional.new
35
- @q.peek_ready.should_not be_nil
35
+ @q.peek(:ready).should_not be_nil
36
36
  lambda{ @q.reserve.perform }.should raise_exception
37
- @q.peek_buried.should_not be_nil
37
+ @q.peek(:buried).should_not be_nil
38
38
  end
39
39
 
40
40
  it "should bury an AR job if an exception occurs deserializing it" do
41
41
  @user = User.new(:first_name => "John", :last_name => "Doe", :email => "jdoe@gmail.com")
42
42
  @user.id = 1
43
43
  @q.put Serializer::ActiveRecord.serialize(@user)
44
- @q.peek_ready.should_not be_nil
44
+ @q.peek(:ready).should_not be_nil
45
45
  lambda{ @q.reserve.perform }.should raise_exception
46
- @q.peek_buried.should_not be_nil
46
+ @q.peek(:buried).should_not be_nil
47
47
  end
48
48
 
49
49
  context "job actions" do
50
50
  it "should delete job" do
51
51
  @q.put DeleteJob.new
52
- @q.peek_ready.should_not be_nil
52
+ @q.peek(:ready).should_not be_nil
53
53
  @q.reserve.perform
54
- @q.peek_ready.should be_nil
54
+ @q.peek(:ready).should be_nil
55
55
  end
56
56
 
57
57
  it "should release job" do
58
58
  @q.put ReleaseJob.new
59
- @q.peek_ready.should_not be_nil
59
+ @q.peek(:ready).should_not be_nil
60
60
  @q.reserve.perform
61
- @q.peek_ready.should_not be_nil
61
+ @q.peek(:ready).should_not be_nil
62
62
  end
63
63
 
64
64
  it "should bury job" do
65
65
  @q.put BuryJob.new
66
- @q.peek_ready.should_not be_nil
67
- @q.peek_buried.should be_nil
66
+ @q.peek(:ready).should_not be_nil
67
+ @q.peek(:buried).should be_nil
68
68
  @q.reserve.perform
69
- @q.peek_ready.should be_nil
70
- @q.peek_buried.should_not be_nil
69
+ @q.peek(:ready).should be_nil
70
+ @q.peek(:buried).should_not be_nil
71
71
  end
72
72
  end
73
73
 
74
74
  it "should retry a job with a delay and then bury" do
75
75
  TimeoutJob.backend = @q
76
76
  TimeoutJob.new.enqueue
77
- @q.peek_ready.should_not be_nil
77
+ @q.peek(:ready).should_not be_nil
78
78
  job = @q.reserve
79
79
  job.beanstalk_job.stats["releases"].should eql(0)
80
80
  job.beanstalk_job.stats["delay"].should eql(0)
81
81
  lambda{job.perform}.should raise_exception(Quebert::Job::Timeout)
82
82
 
83
- @q.peek_ready.should be_nil
84
- beanstalk_job = @q.peek_delayed
83
+ @q.peek(:ready).should be_nil
84
+ beanstalk_job = @q.peek(:delayed)
85
85
  beanstalk_job.should_not be_nil
86
86
  beanstalk_job.stats["releases"].should eql(1)
87
87
  beanstalk_job.stats["delay"].should eql(Quebert::Controller::Beanstalk::TIMEOUT_RETRY_GROWTH_RATE**beanstalk_job.stats["releases"])
@@ -92,8 +92,8 @@ describe Controller::Beanstalk do
92
92
  Quebert::Controller::Beanstalk::MAX_TIMEOUT_RETRY_DELAY = 1
93
93
  lambda{@q.reserve.perform}.should raise_exception(Quebert::Job::Timeout)
94
94
 
95
- @q.peek_ready.should be_nil
96
- @q.peek_delayed.should be_nil
97
- @q.peek_buried.should_not be_nil
95
+ @q.peek(:ready).should be_nil
96
+ @q.peek(:delayed).should be_nil
97
+ @q.peek(:buried).should_not be_nil
98
98
  end
99
99
  end
data/spec/worker_spec.rb CHANGED
@@ -7,11 +7,11 @@ describe Worker do
7
7
  w.backend = @q
8
8
  end
9
9
  end
10
-
10
+
11
11
  it "should start" do
12
12
  @w.start
13
13
  end
14
-
14
+
15
15
  context "pluggable exception handler" do
16
16
  it "should raise exception if nothing is provided" do
17
17
  @q.put Exceptional.new
@@ -20,15 +20,14 @@ describe Worker do
20
20
 
21
21
  it "should default to Quebert.config.worker.exception_handler handler" do
22
22
  @q.put Exceptional.new
23
- Quebert.config.worker.exception_handler = Proc.new{|e| e.should be_instance_of(Exception) }
24
- @w.exception_handler = Proc.new{|e| e.should be_instance_of(Exception) }
23
+ Quebert.config.worker.exception_handler = Proc.new{|e, opts| e.should be_instance_of(Exception) }
25
24
  lambda{ @w.start }.should_not raise_exception
26
25
  end
27
-
26
+
28
27
  it "should intercept exceptions" do
29
28
  @q.put Exceptional.new
30
- @w.exception_handler = Proc.new{|e| e.should be_instance_of(Exception) }
29
+ @w.exception_handler = Proc.new{|e, opts| e.should be_instance_of(Exception) }
31
30
  lambda{ @w.start }.should_not raise_exception
32
31
  end
33
32
  end
34
- end
33
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quebert
3
3
  version: !ruby/object:Gem::Version
4
- hash: 5
4
+ hash: 59
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
+ - 11
8
9
  - 0
9
- - 9
10
- version: 1.0.9
10
+ version: 1.11.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Brad Gessler
@@ -17,7 +17,8 @@ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
19
 
20
- date: 2012-06-06 00:00:00 Z
20
+ date: 2012-12-21 00:00:00 -06:00
21
+ default_executable:
21
22
  dependencies:
22
23
  - !ruby/object:Gem::Dependency
23
24
  name: json
@@ -34,7 +35,7 @@ dependencies:
34
35
  type: :runtime
35
36
  version_requirements: *id001
36
37
  - !ruby/object:Gem::Dependency
37
- name: beanstalk-client
38
+ name: beaneater
38
39
  prerelease: false
39
40
  requirement: &id002 !ruby/object:Gem::Requirement
40
41
  none: false
@@ -121,6 +122,7 @@ files:
121
122
  - spec/support/jobs.rb
122
123
  - spec/support_spec.rb
123
124
  - spec/worker_spec.rb
125
+ has_rdoc: true
124
126
  homepage: http://github.com/polleverywhere/quebert
125
127
  licenses: []
126
128
 
@@ -150,7 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
150
152
  requirements: []
151
153
 
152
154
  rubyforge_project: quebert
153
- rubygems_version: 1.8.22
155
+ rubygems_version: 1.6.2
154
156
  signing_key:
155
157
  specification_version: 3
156
158
  summary: A worker queue framework built around beanstalkd