ayl-beanstalk 0.1.8 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -2,7 +2,7 @@ source "http://rubygems.org"
2
2
  # Add dependencies required to use your gem here.
3
3
  # Example:
4
4
  # gem "activesupport", ">= 2.3.5"
5
- gem 'ayl', ">= 0.1.0"
5
+ gem 'ayl', ">= 0.2.1"
6
6
  gem 'beanstalk-client', ">= 1.1.0"
7
7
  gem 'daemons', ">= 1.1.0"
8
8
 
data/Gemfile.lock CHANGED
@@ -30,7 +30,7 @@ GEM
30
30
  activesupport (3.1.2)
31
31
  multi_json (~> 1.0)
32
32
  arel (2.2.1)
33
- ayl (0.1.0)
33
+ ayl (0.2.1)
34
34
  beanstalk-client (1.1.1)
35
35
  builder (3.0.0)
36
36
  coderay (0.9.8)
@@ -114,7 +114,7 @@ PLATFORMS
114
114
  ruby
115
115
 
116
116
  DEPENDENCIES
117
- ayl (>= 0.1.0)
117
+ ayl (>= 0.2.1)
118
118
  beanstalk-client (>= 1.1.0)
119
119
  bundler (>= 1.0.0)
120
120
  daemons (>= 1.1.0)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.8
1
+ 0.2.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "ayl-beanstalk"
8
- s.version = "0.1.8"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["j0hnds@gmail.com"]
12
- s.date = "2013-02-25"
12
+ s.date = "2013-07-22"
13
13
  s.description = "Ayl extension to provide beanstalk support."
14
14
  s.email = "j0hnds@gmail.com"
15
15
  s.executables = ["ayl_beanstalk", "ayl_worker", "ayl_worker_control"]
@@ -54,7 +54,7 @@ Gem::Specification.new do |s|
54
54
  s.specification_version = 3
55
55
 
56
56
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
57
- s.add_runtime_dependency(%q<ayl>, [">= 0.1.0"])
57
+ s.add_runtime_dependency(%q<ayl>, [">= 0.2.1"])
58
58
  s.add_runtime_dependency(%q<beanstalk-client>, [">= 1.1.0"])
59
59
  s.add_runtime_dependency(%q<daemons>, [">= 1.1.0"])
60
60
  s.add_development_dependency(%q<rspec>, [">= 2.3.0"])
@@ -63,7 +63,7 @@ Gem::Specification.new do |s|
63
63
  s.add_development_dependency(%q<rcov>, [">= 0"])
64
64
  s.add_development_dependency(%q<pry>, [">= 0"])
65
65
  else
66
- s.add_dependency(%q<ayl>, [">= 0.1.0"])
66
+ s.add_dependency(%q<ayl>, [">= 0.2.1"])
67
67
  s.add_dependency(%q<beanstalk-client>, [">= 1.1.0"])
68
68
  s.add_dependency(%q<daemons>, [">= 1.1.0"])
69
69
  s.add_dependency(%q<rspec>, [">= 2.3.0"])
@@ -73,7 +73,7 @@ Gem::Specification.new do |s|
73
73
  s.add_dependency(%q<pry>, [">= 0"])
74
74
  end
75
75
  else
76
- s.add_dependency(%q<ayl>, [">= 0.1.0"])
76
+ s.add_dependency(%q<ayl>, [">= 0.2.1"])
77
77
  s.add_dependency(%q<beanstalk-client>, [">= 1.1.0"])
78
78
  s.add_dependency(%q<daemons>, [">= 1.1.0"])
79
79
  s.add_dependency(%q<rspec>, [">= 2.3.0"])
@@ -36,6 +36,7 @@ module Ayl
36
36
  pool.yput(message.to_hash, message.options.priority, message.options.delay, message.options.time_to_run)
37
37
  rescue Exception => ex
38
38
  logger.error "Error submitting message to beanstalk: #{ex}"
39
+ Ayl::Mailer.instance.deliver_message("Error submitting message to beanstalk", ex)
39
40
  end
40
41
  end
41
42
  end
@@ -14,40 +14,73 @@ module Ayl
14
14
 
15
15
  def process_messages
16
16
  logger.debug "#{self.class.name} entering process_messages loop watching: #{Ayl::MessageOptions.default_queue_name}"
17
- # trap('TERM') { puts "## Got the term signal"; @stop = true }
18
- # trap('INT') { puts "## Got the int signal"; @stop = true }
19
17
  # Set the queue that we will be watching
20
18
  pool.watch(Ayl::MessageOptions.default_queue_name)
21
19
  while true
22
20
  break if @stop
23
- job = pool.reserve
21
+ job = nil
22
+ begin
23
+ job = pool.reserve
24
+ rescue Exception => ex
25
+ logger.error "#{self.class.name} Exception in process_messages: #{ex}\n#{ex.backtrace.join("\n")}"
26
+ Ayl::Mailer.instance.deliver_message("#{self.class.name} Exception in process_messages.", ex)
27
+ delete_job(job) unless job.nil?
28
+ next
29
+ end
24
30
  break if job.nil?
31
+ msg = nil
25
32
  begin
26
- process_message(Ayl::Message.from_hash(job.ybody))
27
- job.delete
33
+ msg = Ayl::Message.from_hash(job.ybody)
34
+ process_message(msg)
35
+ delete_job(job)
28
36
  rescue Ayl::UnrecoverableMessageException => ex
29
37
  logger.error "#{self.class.name} Unrecoverable exception in process_messages: #{ex}"
30
- job.delete
38
+ Ayl::Mailer.instance.deliver_message("#{self.class.name} Unrecoverable exception in process_messages", ex)
39
+ delete_job(job)
31
40
  rescue SystemExit
32
41
  # This exception is raised when 'Kernel.exit' is called. In this case
33
42
  # we want to make sure the job is deleted, then we simply re-raise
34
43
  # the exception and we go bye-bye.
35
- job.delete
44
+ delete_job(job)
36
45
  raise
37
46
  rescue Exception => ex
38
47
  logger.error "#{self.class.name} Exception in process_messages: #{ex}\n#{ex.backtrace.join("\n")}"
39
- logger.debug "Age of job: #{job.age}"
40
- if job.age > 60
41
- logger.debug "Deleting job"
42
- job.delete
48
+ if msg.options.decay_failed_job
49
+ handle_job_decay(job, ex)
43
50
  else
44
- logger.debug "Decaying job"
45
- job.decay
51
+ delete_job(job)
52
+ Ayl::Mailer.instance.deliver_message("#{self.class.name} Exception in process_messages.", ex)
46
53
  end
47
54
  end
48
55
  end
49
56
  end
50
57
 
58
+ def handle_job_decay(job, ex)
59
+ logger.debug "Age of job: #{job.age}"
60
+ if job.age > 60
61
+ Ayl::Mailer.instance.deliver_message("#{self.class.name} Deleting decayed job; it just took too long.", ex)
62
+ logger.debug "Deleting job"
63
+ delete_job(job)
64
+ else
65
+ logger.debug "Decaying job"
66
+ decay_job(job)
67
+ end
68
+ end
69
+
70
+ def delete_job(job)
71
+ job.delete
72
+ rescue RuntimeError => ex
73
+ logger.error "#{self.class.name} Error deleting job: #{ex}\n#{ex.backtrace.join("\n")}"
74
+ Ayl::Mailer.instance.deliver_message("#{self.class.name} Error deleting job", ex)
75
+ end
76
+
77
+ def decay_job(job)
78
+ job.decay
79
+ rescue RuntimeError => ex
80
+ logger.error "#{self.class.name} Error decaying job: #{ex}\n#{ex.backtrace.join("\n")}"
81
+ Ayl::Mailer.instance.deliver_message("#{self.class.name} Error decaying job", ex)
82
+ end
83
+
51
84
  end
52
85
 
53
86
  end
@@ -13,14 +13,14 @@ describe 'ayl_worker_control script' do
13
13
 
14
14
  it "should honor the use of the -a option to name the daemon" do
15
15
  ARGV.concat [ '--', '--pid-path', '/tmp', '--name', 'the_name' ]
16
- Daemons.should_receive(:run).with(anything, { :log_dir => '/tmp', :log_output => true, :dir_mode => :normal, :dir => '/tmp', :app_name => 'the_name' })
16
+ Daemons.should_receive(:run).with(anything, { :log_dir => '/tmp', :log_output => true, :dir_mode => :normal, :dir => '/tmp', :multiple => true, :app_name => 'the_name' })
17
17
 
18
18
  load(@ayl_control_script, true)
19
19
  end
20
20
 
21
21
  it "should assume the use of the script for the daemon name if no name argument is specified" do
22
22
  ARGV.concat [ '--', '--pid-path', '/tmp' ]
23
- Daemons.should_receive(:run).with(anything, { :log_dir => '/tmp', :log_output => true, :dir_mode => :normal, :dir => '/tmp' })
23
+ Daemons.should_receive(:run).with(anything, { :log_dir => '/tmp', :log_output => true, :dir_mode => :normal, :dir => '/tmp', :multiple => true })
24
24
 
25
25
  load(@ayl_control_script, true)
26
26
  end
data/spec/engine_spec.rb CHANGED
@@ -11,6 +11,7 @@ describe Ayl::Beanstalk::Engine do
11
11
  Kernel.stub(:puts)
12
12
  @engine = Ayl::Beanstalk::Engine.new
13
13
  @engine.stub_chain(:logger, :info)
14
+ @engine.stub_chain(:logger, :debug)
14
15
  @engine.stub_chain(:logger, :error)
15
16
  end
16
17
 
@@ -46,7 +47,7 @@ describe Ayl::Beanstalk::Engine do
46
47
  it "should submit the specified message to beanstalk" do
47
48
  mock_pool = mock("Beanstalk::Pool")
48
49
  mock_pool.should_receive(:use).with("default")
49
- mock_pool.should_receive(:yput).with( { :type => :ayl, :code => "23.to_s(2)" }, 512, 0, 120)
50
+ mock_pool.should_receive(:yput).with( { :type => :ayl, :decay_failed_job => false, :code => "23.to_s(2)" }, 512, 0, 120)
50
51
 
51
52
  ::Beanstalk::Pool.should_receive(:new).with([ "localhost:11300" ]).and_return(mock_pool)
52
53
 
data/spec/worker_spec.rb CHANGED
@@ -12,6 +12,7 @@ describe Ayl::Beanstalk::Worker do
12
12
  @worker = Ayl::Beanstalk::Worker.new
13
13
  @worker.stub_chain(:logger, :info)
14
14
  @worker.stub_chain(:logger, :error)
15
+ @worker.stub_chain(:logger, :debug)
15
16
  Ayl::MessageOptions.default_queue_name = 'default'
16
17
  end
17
18
 
@@ -90,6 +91,32 @@ describe Ayl::Beanstalk::Worker do
90
91
  @worker.process_messages
91
92
  end
92
93
 
94
+ it "should not decay a job that receives an active-record exception when the default message options are used" do
95
+ mock_job = mock("Beanstalk::Job")
96
+ mock_job.should_not_receive(:decay)
97
+ mock_job.should_receive(:ybody).and_return({ :type => :ayl, :code => "Dog" })
98
+ mock_job.should_not_receive(:age)
99
+ mock_job.should_receive(:delete)
100
+
101
+ mock_pool = mock("Beanstalk::Pool")
102
+ mock_pool.should_receive(:watch).with("default")
103
+ mock_pool.should_receive(:reserve).and_return(mock_job, nil)
104
+
105
+ mock_message = mock("Ayl::Message")
106
+ mock_message.should_receive(:evaluate).and_raise(ActiveRecord::RecordNotFound)
107
+ mock_message.should_receive(:options).and_return do
108
+ mock("Options").tap do | mock_opts |
109
+ mock_opts.should_receive(:decay_failed_job).and_return(false)
110
+ end
111
+ end
112
+ Ayl::Message.stub(:from_hash).with({ :type => :ayl, :code => "Dog" }).and_return(mock_message)
113
+
114
+ ::Beanstalk::Pool.should_receive(:new).with([ "localhost:11300" ]).and_return(mock_pool)
115
+
116
+ @worker.process_messages
117
+
118
+ end
119
+
93
120
  it "should decay a job that receives an active-record exception on receipt of message that is less than 60 seconds old" do
94
121
  mock_job = mock("Beanstalk::Job")
95
122
  mock_job.should_receive(:decay)
@@ -102,6 +129,11 @@ describe Ayl::Beanstalk::Worker do
102
129
 
103
130
  mock_message = mock("Ayl::Message")
104
131
  mock_message.should_receive(:evaluate).and_raise(ActiveRecord::RecordNotFound)
132
+ mock_message.should_receive(:options).and_return do
133
+ mock("Options").tap do | mock_opts |
134
+ mock_opts.should_receive(:decay_failed_job).and_return(true)
135
+ end
136
+ end
105
137
  Ayl::Message.stub(:from_hash).with({ :type => :ayl, :code => "Dog" }).and_return(mock_message)
106
138
 
107
139
  ::Beanstalk::Pool.should_receive(:new).with([ "localhost:11300" ]).and_return(mock_pool)
@@ -121,12 +153,77 @@ describe Ayl::Beanstalk::Worker do
121
153
 
122
154
  mock_message = mock("Ayl::Message")
123
155
  mock_message.should_receive(:evaluate).and_raise(ActiveRecord::RecordNotFound)
156
+ mock_message.should_receive(:options).and_return do
157
+ mock("Options").tap do | mock_opts |
158
+ mock_opts.should_receive(:decay_failed_job).and_return(true)
159
+ end
160
+ end
124
161
  Ayl::Message.stub(:from_hash).with({ :type => :ayl, :code => "Dog" }).and_return(mock_message)
125
162
 
126
163
  ::Beanstalk::Pool.should_receive(:new).with([ "localhost:11300" ]).and_return(mock_pool)
127
164
 
128
165
  @worker.process_messages
129
166
  end
167
+
168
+ it "should not attempt to decay the job if there is a problem deleting a job after the message is successfully processed" do
169
+
170
+ mock_job = mock("Beanstalk::Job")
171
+ mock_job.should_receive(:delete).and_raise("Delete failed for some reason")
172
+ mock_job.should_receive(:ybody).and_return({ :type => :ayl, :code => "23.to_s(2)" })
173
+ mock_job.should_not_receive(:age)
174
+
175
+ mock_pool = mock("Beanstalk::Pool")
176
+ mock_pool.should_receive(:watch).with("default")
177
+ mock_pool.should_receive(:reserve).and_return(mock_job, nil)
178
+
179
+ mock_message = mock("Ayl::Message")
180
+ mock_message.should_receive(:evaluate)
181
+ Ayl::Message.stub(:from_hash).with({ :type => :ayl, :code => "23.to_s(2)" }).and_return(mock_message)
182
+
183
+ ::Beanstalk::Pool.should_receive(:new).with([ "localhost:11300" ]).and_return(mock_pool)
184
+
185
+ expect { @worker.process_messages }.not_to raise_error
186
+ end
187
+ end
188
+
189
+ context '#delete_job' do
190
+
191
+ before(:each) do
192
+ Kernel.stub(:puts)
193
+ @worker = Ayl::Beanstalk::Worker.new
194
+ @worker.stub_chain(:logger, :info)
195
+ @worker.stub_chain(:logger, :error)
196
+ @worker.stub_chain(:logger, :debug)
197
+ Ayl::MessageOptions.default_queue_name = 'default'
198
+ end
199
+
200
+ it "should not raise an exception if the job.delete fail" do
201
+ mock_job = mock("Job")
202
+ mock_job.should_receive(:delete).and_raise("Delete failed for some reason")
203
+
204
+ expect { @worker.delete_job(mock_job) }.not_to raise_error
205
+ end
206
+
207
+ end
208
+
209
+ context '#decay_job' do
210
+
211
+ before(:each) do
212
+ Kernel.stub(:puts)
213
+ @worker = Ayl::Beanstalk::Worker.new
214
+ @worker.stub_chain(:logger, :info)
215
+ @worker.stub_chain(:logger, :error)
216
+ @worker.stub_chain(:logger, :debug)
217
+ Ayl::MessageOptions.default_queue_name = 'default'
218
+ end
219
+
220
+ it "should not raise an exception if the job.delete fail" do
221
+ mock_job = mock("Job")
222
+ mock_job.should_receive(:decay).and_raise("Decay failed for some reason")
223
+
224
+ expect { @worker.decay_job(mock_job) }.not_to raise_error
225
+ end
226
+
130
227
  end
131
228
 
132
229
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ayl-beanstalk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-25 00:00:00.000000000 Z
12
+ date: 2013-07-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ayl
@@ -18,7 +18,7 @@ dependencies:
18
18
  requirements:
19
19
  - - ! '>='
20
20
  - !ruby/object:Gem::Version
21
- version: 0.1.0
21
+ version: 0.2.1
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ! '>='
28
28
  - !ruby/object:Gem::Version
29
- version: 0.1.0
29
+ version: 0.2.1
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: beanstalk-client
32
32
  requirement: !ruby/object:Gem::Requirement
@@ -190,7 +190,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
190
190
  version: '0'
191
191
  segments:
192
192
  - 0
193
- hash: -880016066289096428
193
+ hash: 2726199589731342968
194
194
  required_rubygems_version: !ruby/object:Gem::Requirement
195
195
  none: false
196
196
  requirements: