bumbleworks 0.0.40 → 0.0.41

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
@@ -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