dtsato-pipeline 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,12 @@
1
+ 0.0.8
2
+ =====
3
+
4
+ Bug Fix:
5
+ * Clearing message when restarting a failed stage
6
+ * Only saves the pipeline if it's a new record (client code is free to pass an already saved pipeline if needed)
7
+ * Capturing generic Exception instead of StandardError (in case of Interrupts, Timeouts, ...)
8
+ * Auto-recovering from errors was failing on InvalidStatusError. Added a new :retry status to differentiate between a paused or auto-recoverable error
9
+
1
10
  0.0.7
2
11
  =====
3
12
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.7
1
+ 0.0.8
@@ -1,6 +1,4 @@
1
- require File.join(File.dirname(__FILE__), '..', 'init')
2
- require File.join(File.dirname(__FILE__), '..', 'spec', 'database_integration_helper')
3
- ActiveRecord::Base.logger = Logger.new(STDOUT)
1
+ require File.join(File.dirname(__FILE__), 'helper')
4
2
 
5
3
  class Step1 < Pipeline::Stage::Base
6
4
  def run
@@ -32,4 +30,7 @@ end
32
30
 
33
31
  Pipeline.start(TwoStepPipeline.new)
34
32
 
35
- Delayed::Worker.new.start
33
+ Delayed::Job.work_off
34
+ # Waiting for second job to pass re-scheduling time limit
35
+ sleep(10)
36
+ Delayed::Job.work_off
@@ -1,6 +1,4 @@
1
- require File.join(File.dirname(__FILE__), '..', 'init')
2
- require File.join(File.dirname(__FILE__), '..', 'spec', 'database_integration_helper')
3
- ActiveRecord::Base.logger = Logger.new(STDOUT)
1
+ require File.join(File.dirname(__FILE__), 'helper')
4
2
 
5
3
  class Step1 < Pipeline::Stage::Base
6
4
  def run
@@ -24,9 +22,7 @@ end
24
22
 
25
23
  id = Pipeline.start(TwoStepPipeline.new)
26
24
 
27
- Delayed::Worker.new.start
25
+ Delayed::Job.work_off
28
26
 
29
- # CTRL-C to execute the cancelling, since we want to cancel after the stage failed, but
30
- # Worker is blocking the process on the previous line
31
27
  Pipeline.cancel(id)
32
- p Pipeline::Base.find(id)
28
+ puts("Pipeline is now #{Pipeline::Base.find(id).status}")
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ gem 'activerecord'
3
+ gem 'collectiveidea-delayed_job', :lib => 'delayed_job'
4
+
5
+ require File.join(File.dirname(__FILE__), '..', 'init')
6
+ require File.join(File.dirname(__FILE__), '..', 'spec', 'database_integration_helper')
7
+ ActiveRecord::Base.logger = Logger.new(STDOUT)
@@ -1,6 +1,4 @@
1
- require File.join(File.dirname(__FILE__), '..', 'init')
2
- require File.join(File.dirname(__FILE__), '..', 'spec', 'database_integration_helper')
3
- ActiveRecord::Base.logger = Logger.new(STDOUT)
1
+ require File.join(File.dirname(__FILE__), 'helper')
4
2
 
5
3
  class Step1 < Pipeline::Stage::Base
6
4
  def run
@@ -24,4 +22,4 @@ end
24
22
 
25
23
  Pipeline.start(TwoStepPipeline.new)
26
24
 
27
- Delayed::Worker.new.start
25
+ Delayed::Job.work_off
@@ -1,6 +1,4 @@
1
- require File.join(File.dirname(__FILE__), '..', 'init')
2
- require File.join(File.dirname(__FILE__), '..', 'spec', 'database_integration_helper')
3
- ActiveRecord::Base.logger = Logger.new(STDOUT)
1
+ require File.join(File.dirname(__FILE__), 'helper')
4
2
 
5
3
  class Step1 < Pipeline::Stage::Base
6
4
  def run
@@ -28,6 +26,8 @@ end
28
26
 
29
27
  id = Pipeline.start(TwoStepPipeline.new)
30
28
 
29
+ Delayed::Job.work_off
30
+
31
31
  Pipeline.resume(id)
32
32
 
33
- Delayed::Worker.new.start
33
+ Delayed::Job.work_off
@@ -2,7 +2,7 @@ module Pipeline
2
2
  module ApiMethods
3
3
  def start(pipeline)
4
4
  raise InvalidPipelineError.new("Invalid pipeline") unless pipeline.is_a?(Pipeline::Base)
5
- pipeline.save!
5
+ pipeline.save! if pipeline.new_record?
6
6
  Delayed::Job.enqueue(pipeline)
7
7
  pipeline.id
8
8
  end
data/lib/pipeline/base.rb CHANGED
@@ -5,7 +5,7 @@ module Pipeline
5
5
  # :not_started ---> :in_progress ---> :completed
6
6
  # ^ | \-> :failed
7
7
  # | v
8
- # :paused
8
+ # :paused / :retry
9
9
  symbol_attr :status
10
10
  transactional_attr :status
11
11
  private :status=
@@ -28,8 +28,8 @@ module Pipeline
28
28
  end
29
29
 
30
30
  def after_initialize
31
- self[:status] = :not_started if new_record?
32
31
  if new_record?
32
+ self[:status] = :not_started
33
33
  self.class.defined_stages.each do |stage_class|
34
34
  stages << stage_class.new(:pipeline => self)
35
35
  end
@@ -51,9 +51,10 @@ module Pipeline
51
51
  if e.input_required?
52
52
  self.status = :paused
53
53
  else
54
+ self.status = :retry
54
55
  raise e
55
56
  end
56
- rescue
57
+ rescue Exception
57
58
  self.status = (failure_mode == :cancel ? :failed : :paused)
58
59
  end
59
60
  end
@@ -64,7 +65,7 @@ module Pipeline
64
65
  end
65
66
 
66
67
  def ok_to_resume?
67
- [:not_started, :paused].include?(status)
68
+ [:not_started, :paused, :retry].include?(status)
68
69
  end
69
70
 
70
71
  private
@@ -28,8 +28,10 @@ module Pipeline
28
28
  class_inheritable_accessor :default_name, :instance_writer => false
29
29
 
30
30
  def after_initialize
31
- self.name ||= (default_name || self.class).to_s
32
- self[:status] = :not_started if new_record?
31
+ if new_record?
32
+ self[:status] = :not_started
33
+ self.name ||= (default_name || self.class).to_s
34
+ end
33
35
  end
34
36
 
35
37
  def completed?
@@ -43,7 +45,7 @@ module Pipeline
43
45
  _setup
44
46
  run
45
47
  self.status = :completed
46
- rescue => e
48
+ rescue Exception => e
47
49
  logger.info("Error on stage #{default_name}: #{e.message}")
48
50
  logger.info(e.backtrace.join("\n"))
49
51
  self.message = e.message
@@ -58,6 +60,7 @@ module Pipeline
58
60
  private
59
61
  def _setup
60
62
  self.attempts += 1
63
+ self.message = nil
61
64
  self.status = :in_progress
62
65
  end
63
66
  end
data/pipeline.gemspec CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{pipeline}
5
- s.version = "0.0.7"
5
+ s.version = "0.0.8"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Danilo Sato"]
9
- s.date = %q{2009-08-18}
9
+ s.date = %q{2009-08-20}
10
10
  s.description = %q{Pipeline is a Rails plugin/gem to run asynchronous processes in a configurable pipeline.}
11
11
  s.email = %q{danilo@dtsato.com}
12
12
  s.extra_rdoc_files = [
@@ -22,6 +22,7 @@ Gem::Specification.new do |s|
22
22
  "VERSION",
23
23
  "examples/auto_recoverable_pipeline.rb",
24
24
  "examples/cancelling_pipeline.rb",
25
+ "examples/helper.rb",
25
26
  "examples/two_step_pipeline.rb",
26
27
  "examples/user_recoverable_pipeline.rb",
27
28
  "generators/pipeline/pipeline_generator.rb",
@@ -8,7 +8,7 @@ module Pipeline
8
8
  describe "#start" do
9
9
  before(:each) do
10
10
  @pipeline = FakePipeline.new
11
- @pipeline.stub!(:save!)
11
+ @pipeline.stub!(:new_record?).and_return(false)
12
12
  Delayed::Job.stub!(:enqueue)
13
13
  end
14
14
 
@@ -17,12 +17,20 @@ module Pipeline
17
17
  lambda {Pipeline.start(Object.new)}.should raise_error(InvalidPipelineError, "Invalid pipeline")
18
18
  end
19
19
 
20
- it "should save pipeline instance" do
20
+ it "should save pipeline instance (for new record)" do
21
+ @pipeline.should_receive(:new_record?).and_return(true)
21
22
  @pipeline.should_receive(:save!)
22
23
 
23
24
  Pipeline.start(@pipeline)
24
25
  end
25
26
 
27
+ it "should not save pipeline instance (if already saved)" do
28
+ @pipeline.should_receive(:new_record?).and_return(false)
29
+ @pipeline.should_not_receive(:save!)
30
+
31
+ Pipeline.start(@pipeline)
32
+ end
33
+
26
34
  it "should start a job for a pipeline instance" do
27
35
  Delayed::Job.should_receive(:enqueue).with(@pipeline)
28
36
 
@@ -36,7 +36,7 @@ end
36
36
  class GenericErrorStage < FirstStage
37
37
  def run
38
38
  super
39
- raise StandardError.new
39
+ raise Exception.new
40
40
  end
41
41
  end
42
42
 
@@ -229,15 +229,15 @@ module Pipeline
229
229
  lambda {@pipeline.perform}.should raise_error(RecoverableError)
230
230
  end
231
231
 
232
- it "should keep status :in_progress" do
232
+ it "should change status to :retry" do
233
233
  lambda {@pipeline.perform}.should raise_error(RecoverableError)
234
- @pipeline.status.should == :in_progress
234
+ @pipeline.status.should == :retry
235
235
  end
236
236
 
237
237
  it "should save status" do
238
238
  @pipeline.save!
239
239
  lambda {@pipeline.perform}.should raise_error(RecoverableError)
240
- @pipeline.reload.status.should == :in_progress
240
+ @pipeline.reload.status.should == :retry
241
241
  end
242
242
  end
243
243
 
@@ -274,7 +274,7 @@ module Pipeline
274
274
  end
275
275
 
276
276
  it "should not re-raise error" do
277
- lambda {@pipeline.perform}.should_not raise_error(StandardError)
277
+ lambda {@pipeline.perform}.should_not raise_error(Exception)
278
278
  end
279
279
 
280
280
  it "should update status (pause mode)" do
@@ -368,6 +368,13 @@ module Pipeline
368
368
  @pipeline.should be_ok_to_resume
369
369
  lambda {@pipeline.perform}.should_not raise_error(InvalidStatusError)
370
370
  end
371
+
372
+ it "should execute if status is :retry" do
373
+ @pipeline.send(:status=, :retry)
374
+
375
+ @pipeline.should be_ok_to_resume
376
+ lambda {@pipeline.perform}.should_not raise_error(InvalidStatusError)
377
+ end
371
378
 
372
379
  it "should not execute if status is :in_progress" do
373
380
  @pipeline.send(:status=, :in_progress)
@@ -173,6 +173,13 @@ module Pipeline
173
173
  @stage.reload.message.should == "message"
174
174
  end
175
175
 
176
+ it "should capture generic Exception" do
177
+ @stage.should_receive(:run).and_raise(Exception.new)
178
+ lambda {@stage.perform}.should raise_error(Exception)
179
+ @stage.status.should == :failed
180
+ @stage.reload.status.should == :failed
181
+ end
182
+
176
183
  it "should log exception message and backtrace" do
177
184
  SampleStage.default_name = "SampleStage"
178
185
  error = StandardError.new("error message")
@@ -209,6 +216,14 @@ module Pipeline
209
216
  stage.status.should == :in_progress
210
217
  stage.reload.status.should == :in_progress
211
218
  end
219
+
220
+ it "should clear message when restarting" do
221
+ stage = SampleStage.new(:message => 'some message')
222
+ stage.send(:_setup)
223
+
224
+ stage.message.should be_nil
225
+ stage.reload.message.should be_nil
226
+ end
212
227
  end
213
228
 
214
229
  describe "- execution (state transitions)" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dtsato-pipeline
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Danilo Sato
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-08-18 00:00:00 -07:00
12
+ date: 2009-08-20 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -50,6 +50,7 @@ files:
50
50
  - VERSION
51
51
  - examples/auto_recoverable_pipeline.rb
52
52
  - examples/cancelling_pipeline.rb
53
+ - examples/helper.rb
53
54
  - examples/two_step_pipeline.rb
54
55
  - examples/user_recoverable_pipeline.rb
55
56
  - generators/pipeline/pipeline_generator.rb