bumbleworks 0.0.40 → 0.0.41

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -2,3 +2,4 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in bumbleworks.gemspec
4
4
  gemspec
5
+ gem "rufus-scheduler", "~> 2.0"
data/README.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Bumbleworks
2
2
 
3
+ **IMPORTANT**: Ruote (a dependency of Bumbleworks) currently has a bug in its dependency graph. Until this is fixed (and we'll update this readme when it is), make sure you add this to your gemfile:
4
+
5
+ ```ruby
6
+ gem 'rufus-scheduler', '~> 2.0'
7
+ ```
8
+
3
9
  **NOTE**: This product is still pre-release, and implementation is *not* in sync with documentation yet - hence the pre-release version. We'll follow [the Semantic Versioning Specification (Semver)](http://semver.org/), so you can assume anything at 0.x.x still has an unstable API. But we *are* actively developing this.
4
10
 
5
11
  Bumbleworks is a gem that adds a workflow engine (via [ruote](http://github.com/jmettraux/ruote)) to your Ruby application, and adds tools for task authorization and locking. It also establishes conventions for easily loading process definitions and registering participant classes based on configurable file locations.
@@ -197,8 +203,6 @@ See the Bumbleworks::Task class for more details.
197
203
 
198
204
  ## Rake Tasks
199
205
 
200
- *TODO: Actually implement these, so I'm not a liar.*
201
-
202
206
  If you...
203
207
 
204
208
  ```ruby
@@ -10,6 +10,9 @@ require "bumbleworks/hash_storage"
10
10
  require "bumbleworks/simple_logger"
11
11
  require "bumbleworks/storage_participant"
12
12
  require "bumbleworks/local_participant"
13
+ require "bumbleworks/error_handler"
14
+ require "bumbleworks/error_logger"
15
+ require "bumbleworks/error_handler_participant"
13
16
 
14
17
  module Bumbleworks
15
18
  class UnsupportedMode < StandardError; end
@@ -94,6 +94,24 @@ module Bumbleworks
94
94
  # default: 5 seconds
95
95
  define_setting :timeout
96
96
 
97
+ # When errors occur during the exection of a process, errors are captured and dispatched to
98
+ # the registerd error handlers. an error handler derives from the Bumbleworks::ErrorHandler
99
+ # and will receive the error information through the #on_error method.
100
+ #
101
+ # class MySpecialHandler < Bumbleworks::ErrorHandler
102
+ # def on_error
103
+ # p @workitem.error
104
+ # end
105
+ # end
106
+ #
107
+ # For exclusive use:
108
+ # Bumbleworks.error_handlers = [MySpeicalHandler, MySpecialHandler2]
109
+ #
110
+ # To append to exisiting handlers:
111
+ # Bumbleworks.error_handlers << MySpeicalHandler
112
+ #
113
+ define_setting :error_handlers
114
+
97
115
  def initialize
98
116
  @storage_adapters = []
99
117
  @timeout ||= 5
@@ -173,6 +191,10 @@ module Bumbleworks
173
191
  @definitions_folder = @participants_folder = @tasks_folder = nil
174
192
  end
175
193
 
194
+ def error_handlers
195
+ @error_handlers ||= [Bumbleworks::ErrorLogger]
196
+ end
197
+
176
198
  private
177
199
  def defined_settings
178
200
  self.class.defined_settings
@@ -0,0 +1,15 @@
1
+ module Bumbleworks
2
+ class ErrorHandler
3
+ include WorkitemEntityStorage
4
+ class SubclassResponsibility < StandardError; end
5
+
6
+ attr_accessor :workitem
7
+ def initialize(workitem)
8
+ @workitem = workitem
9
+ end
10
+
11
+ def on_error
12
+ raise SubclassResponsibility
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ module Bumbleworks
2
+ class ErrorHandlerParticipant
3
+ include ::Ruote::LocalParticipant
4
+
5
+ def on_workitem
6
+ return if (error_handlers = Bumbleworks.error_handlers).empty?
7
+
8
+ error_handlers.each do |error_handler|
9
+ error_handler.new(workitem).on_error
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,27 @@
1
+ module Bumbleworks
2
+ class ErrorLogger < ErrorHandler
3
+ def on_error
4
+ return unless logger
5
+
6
+ logger.error(
7
+ :actor => @workitem.wf_name,
8
+ :action => 'process error',
9
+ :target_type => entity_fields[:type],
10
+ :target_id => entity_fields[:identifier],
11
+ :metadata => metadata
12
+ )
13
+ end
14
+
15
+ private
16
+ def logger
17
+ Bumbleworks.logger
18
+ end
19
+
20
+ def metadata
21
+ {
22
+ :wfid => @workitem.wfid,
23
+ :error => @workitem.error,
24
+ }
25
+ end
26
+ end
27
+ end
@@ -35,6 +35,7 @@ module Bumbleworks
35
35
  else
36
36
  worker.run_in_thread
37
37
  end
38
+ register_error_handler
38
39
  worker
39
40
  end
40
41
 
@@ -99,9 +100,15 @@ module Bumbleworks
99
100
  def register_participants(&block)
100
101
  dashboard.register(&block) if block
101
102
  set_catchall_if_needed
103
+ register_error_handler
102
104
  dashboard.participant_list
103
105
  end
104
106
 
107
+ def register_error_handler
108
+ dashboard.register_participant :error_handler_participant, Bumbleworks::ErrorHandlerParticipant
109
+ dashboard.on_error = 'error_handler_participant'
110
+ end
111
+
105
112
  def set_catchall_if_needed
106
113
  last_participant = dashboard.participant_list.last
107
114
  unless last_participant && last_participant.regex == "^.+$" &&
@@ -1,3 +1,3 @@
1
1
  module Bumbleworks
2
- VERSION = "0.0.40"
2
+ VERSION = "0.0.41"
3
3
  end
@@ -10,8 +10,8 @@ describe 'Bumbleworks Sample Application' do
10
10
 
11
11
  describe 'initializer' do
12
12
  it 'registers participants' do
13
- Bumbleworks.dashboard.participant_list.should have(3).items
14
- Bumbleworks.dashboard.participant_list.map(&:classname).should =~ ['HoneyParticipant', 'MolassesParticipant', 'Bumbleworks::StorageParticipant']
13
+ Bumbleworks.dashboard.participant_list.should have(4).items
14
+ Bumbleworks.dashboard.participant_list.map(&:classname).should =~ ['HoneyParticipant', 'MolassesParticipant', 'Bumbleworks::ErrorHandlerParticipant', 'Bumbleworks::StorageParticipant']
15
15
  end
16
16
 
17
17
  it 'loads process definitions' do
@@ -249,4 +249,21 @@ describe Bumbleworks::Configuration do
249
249
  configuration.definitions_directory.should == '/Root/lib/bumbleworks/process_definitions'
250
250
  end
251
251
  end
252
+
253
+ describe '#error_handlers', dev:true do
254
+ let(:super_handler) {double('error_handler')}
255
+ it 'sets default error handler' do
256
+ configuration.error_handlers.should == [Bumbleworks::ErrorLogger]
257
+ end
258
+
259
+ it 'replaces default handler' do
260
+ configuration.error_handlers = [super_handler]
261
+ configuration.error_handlers.should == [super_handler]
262
+ end
263
+
264
+ it 'adds to default handler' do
265
+ configuration.error_handlers << super_handler
266
+ configuration.error_handlers.should =~ [Bumbleworks::ErrorLogger, super_handler]
267
+ end
268
+ end
252
269
  end
@@ -0,0 +1,15 @@
1
+ describe Bumbleworks::ErrorHandlerParticipant do
2
+ describe '#on_workitem' do
3
+ let(:workitem) { double('workitem') }
4
+ let(:instances) { [double(:on_error => nil), double(:on_error => nil)] }
5
+ let(:error_handlers) { [double(:new => instances[0]), double(:new => instances[1])] }
6
+
7
+ it 'calls all error handlers passing in workitem' do
8
+ Bumbleworks.error_handlers = error_handlers
9
+ error_handlers[0].should_receive(:new).ordered.with(workitem).and_return(instances[0])
10
+ error_handlers[1].should_receive(:new).ordered.with(workitem).and_return(instances[1])
11
+ subject.stub(:workitem => workitem)
12
+ subject.on_workitem
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ describe Bumbleworks::ErrorHandler do
2
+ subject {described_class.new(workitem)}
3
+ let(:workitem) { double }
4
+ describe '#initialize' do
5
+ it 'sets workitem' do
6
+ subject.workitem.should == workitem
7
+ end
8
+ end
9
+
10
+ describe '#on_error' do
11
+ it 'raises a SubclassResponsiblity exception' do
12
+ expect{subject.on_error}.to raise_error Bumbleworks::ErrorHandler::SubclassResponsibility
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,30 @@
1
+ describe Bumbleworks::ErrorLogger do
2
+ subject {described_class.new(workitem)}
3
+ let(:workitem) {double(:wf_name => 'armadillo', :error => 'something is amiss in dillo land', :wfid => 'zabme123', :fields => {})}
4
+ it 'calls registered logger and logs error information' do
5
+ Bumbleworks.logger.should_receive(:error).with({
6
+ :actor => 'armadillo',
7
+ :action => 'process error',
8
+ :target_type => nil,
9
+ :target_id => nil,
10
+ :metadata => {:wfid => 'zabme123', :error => 'something is amiss in dillo land'}
11
+ })
12
+
13
+ subject.on_error
14
+ end
15
+
16
+ it 'sets target to entity if found' do
17
+ workitem.stub(:fields => {:entity_id => 1234, :entity_type => 'Lizards'})
18
+ Bumbleworks.logger.should_receive(:error).with(hash_including({
19
+ :target_type => 'Lizards',
20
+ :target_id => 1234,
21
+ }))
22
+
23
+ subject.on_error
24
+ end
25
+
26
+ it 'does nothing if logger is not registered' do
27
+ Bumbleworks.stub(:logger)
28
+ subject.on_error.should == nil
29
+ end
30
+ end
@@ -220,6 +220,11 @@ describe Bumbleworks::Ruote do
220
220
  described_class.dashboard.should_receive(:noisy=).with(true)
221
221
  described_class.start_worker!(:verbose => true)
222
222
  end
223
+
224
+ it 'registers error handler' do
225
+ described_class.should_receive(:register_error_handler)
226
+ described_class.start_worker!
227
+ end
223
228
  end
224
229
 
225
230
  describe '.register_participants' do
@@ -232,8 +237,9 @@ describe Bumbleworks::Ruote do
232
237
 
233
238
  described_class.dashboard.participant_list.should be_empty
234
239
  described_class.register_participants &registration_block
235
- described_class.dashboard.participant_list.should have(4).items
236
- described_class.dashboard.participant_list.map(&:classname).should =~ ['BeesHoney', 'MapleSyrup', 'NewCatchall', 'Bumbleworks::StorageParticipant']
240
+ described_class.dashboard.participant_list.should have(5).items
241
+ described_class.dashboard.participant_list.map(&:classname).should =~ [
242
+ 'BeesHoney', 'MapleSyrup', 'NewCatchall', 'Bumbleworks::ErrorHandlerParticipant', 'Bumbleworks::StorageParticipant']
237
243
  end
238
244
 
239
245
  it 'does not add storage participant catchall if already exists' do
@@ -244,18 +250,42 @@ describe Bumbleworks::Ruote do
244
250
 
245
251
  described_class.dashboard.participant_list.should be_empty
246
252
  described_class.register_participants &registration_block
247
- described_class.dashboard.participant_list.should have(2).items
248
- described_class.dashboard.participant_list.map(&:classname).should =~ ['BeesHoney', 'Ruote::StorageParticipant']
253
+ described_class.dashboard.participant_list.should have(3).items
254
+ described_class.dashboard.participant_list.map(&:classname).should =~ [
255
+ 'BeesHoney', 'Bumbleworks::ErrorHandlerParticipant', 'Ruote::StorageParticipant'
256
+ ]
249
257
  end
250
258
 
251
259
  it 'adds catchall participant if block is nil' do
252
260
  described_class.dashboard.participant_list.should be_empty
253
261
  described_class.register_participants &nil
254
- described_class.dashboard.participant_list.should have(1).item
262
+ described_class.dashboard.participant_list.should have(2).item
255
263
  described_class.dashboard.participant_list.first.classname.should == 'Bumbleworks::StorageParticipant'
256
264
  end
257
265
  end
258
266
 
267
+ describe '.register_error_handler', dev:true do
268
+ it 'registers the error handler participant' do
269
+ described_class.register_error_handler
270
+ Bumbleworks.dashboard.participant_list.map(&:classname).should include('Bumbleworks::ErrorHandlerParticipant')
271
+ end
272
+
273
+ it 'it sets the global Ruote on_error to the error_handler_participant' do
274
+ described_class.register_error_handler
275
+ Bumbleworks.dashboard.on_error.flatten[2].should == 'error_handler_participant'
276
+ end
277
+
278
+ it 'skip registration if error_handlers list is missing' do
279
+ described_class.stub(:error_handlers => nil)
280
+ Bumbleworks.dashboard.should_not_receive(:register_participant).with(:error_handler, Bumbleworks::ErrorHandlerParticipant)
281
+ end
282
+
283
+ it 'skip registration if error_handlers list is empty' do
284
+ described_class.stub(:error_handlers => [])
285
+ Bumbleworks.dashboard.should_not_receive(:register_participant).with(:error_handler, Bumbleworks::ErrorHandlerParticipant)
286
+ end
287
+ end
288
+
259
289
  describe '.storage' do
260
290
  it 'raise error when storage is not defined' do
261
291
  Bumbleworks.storage = nil
@@ -79,6 +79,7 @@ describe Bumbleworks do
79
79
  describe '.configuration' do
80
80
  before :each do
81
81
  Bumbleworks.reset!
82
+ Bumbleworks::StorageAdapter.auto_register = nil
82
83
  end
83
84
 
84
85
  it 'creates an instance of Bumbleworks::Configuration' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bumbleworks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.40
4
+ version: 0.0.41
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2013-10-29 00:00:00.000000000 Z
15
+ date: 2013-11-20 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: ruote
@@ -167,6 +167,9 @@ files:
167
167
  - doc/TERMS.md
168
168
  - lib/bumbleworks.rb
169
169
  - lib/bumbleworks/configuration.rb
170
+ - lib/bumbleworks/error_handler.rb
171
+ - lib/bumbleworks/error_handler_participant.rb
172
+ - lib/bumbleworks/error_logger.rb
170
173
  - lib/bumbleworks/hash_storage.rb
171
174
  - lib/bumbleworks/local_participant.rb
172
175
  - lib/bumbleworks/participant_registration.rb
@@ -204,6 +207,9 @@ files:
204
207
  - spec/integration/configuration_spec.rb
205
208
  - spec/integration/sample_application_spec.rb
206
209
  - spec/lib/bumbleworks/configuration_spec.rb
210
+ - spec/lib/bumbleworks/error_handler_participant_spec.rb
211
+ - spec/lib/bumbleworks/error_handler_spec.rb
212
+ - spec/lib/bumbleworks/error_logger_spec.rb
207
213
  - spec/lib/bumbleworks/local_participant_spec.rb
208
214
  - spec/lib/bumbleworks/participant_registration_spec.rb
209
215
  - spec/lib/bumbleworks/process_definition_spec.rb
@@ -236,7 +242,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
236
242
  version: '0'
237
243
  segments:
238
244
  - 0
239
- hash: -3173447995460527192
245
+ hash: 2565282303718385581
240
246
  required_rubygems_version: !ruby/object:Gem::Requirement
241
247
  none: false
242
248
  requirements:
@@ -245,7 +251,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
245
251
  version: '0'
246
252
  segments:
247
253
  - 0
248
- hash: -3173447995460527192
254
+ hash: 2565282303718385581
249
255
  requirements: []
250
256
  rubyforge_project:
251
257
  rubygems_version: 1.8.23
@@ -271,6 +277,9 @@ test_files:
271
277
  - spec/integration/configuration_spec.rb
272
278
  - spec/integration/sample_application_spec.rb
273
279
  - spec/lib/bumbleworks/configuration_spec.rb
280
+ - spec/lib/bumbleworks/error_handler_participant_spec.rb
281
+ - spec/lib/bumbleworks/error_handler_spec.rb
282
+ - spec/lib/bumbleworks/error_logger_spec.rb
274
283
  - spec/lib/bumbleworks/local_participant_spec.rb
275
284
  - spec/lib/bumbleworks/participant_registration_spec.rb
276
285
  - spec/lib/bumbleworks/process_definition_spec.rb