ruote 2.1.8 → 2.1.9

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.
@@ -2,6 +2,13 @@
2
2
  = ruote - CHANGELOG.txt
3
3
 
4
4
 
5
+ == ruote - 2.1.9 released 2010/03/22
6
+
7
+ - made participant.cancel occur asynchronously (as should be)
8
+ - lookup_variable : making sure not to break when the parent exp is gone
9
+ - workitem.fields['__dispatch_time__'] is now set
10
+
11
+
5
12
  == ruote - 2.1.8 released 2010/03/15
6
13
 
7
14
  - participant#schedule_timeout workaround for issue with JRuby 1.4.0 (1.8.7)
data/TODO.txt CHANGED
@@ -317,3 +317,9 @@
317
317
  else-ref... list of participants...
318
318
  ref="alpha && bravo", ref="alpha||bravo" (|| parallel :( )
319
319
 
320
+ [ ] LocalParticipant def consume; handle; reply; end
321
+
322
+ [ ] lib/ruote/part/participant_list.rb l176 better error message !
323
+
324
+ [ ] find better solution than "get all schedules"
325
+
@@ -149,7 +149,7 @@ module Ruote
149
149
  def process (wfid)
150
150
 
151
151
  exps = @storage.get_many('expressions', /!#{wfid}$/)
152
- errs = @storage.get_many('errors', /!#{wfid}$/)
152
+ errs = self.errors( wfid )
153
153
 
154
154
  return nil if exps.empty? && errs.empty?
155
155
 
@@ -163,7 +163,7 @@ module Ruote
163
163
  def processes
164
164
 
165
165
  exps = @storage.get_many('expressions')
166
- errs = @storage.get_many('errors')
166
+ errs = self.errors
167
167
 
168
168
  by_wfid = {}
169
169
 
@@ -177,6 +177,14 @@ module Ruote
177
177
  by_wfid.values.collect { |xs, rs| ProcessStatus.new(@context, xs, rs) }
178
178
  end
179
179
 
180
+ # Returns an array of current errors (hashes)
181
+ #
182
+ def errors( wfid = nil )
183
+ wfid.nil? ?
184
+ @storage.get_many('errors') :
185
+ @storage.get_many('errors', /!#{wfid}$/)
186
+ end
187
+
180
188
  def shutdown
181
189
 
182
190
  @context.shutdown
@@ -158,29 +158,29 @@ module Ruote::Exp
158
158
  'participant_name' => h.participant_name,
159
159
  'workitem' => h.applied_workitem,
160
160
  'for_engine_worker?' => participant_info.class != Array)
161
+ #
162
+ # NOTE : is this for_engine_worker? still necessary ?
161
163
  end
162
164
 
163
165
  def cancel (flavour)
164
166
 
165
- participant = @context.plist.lookup(h.participant_name)
166
-
167
- r = if flavour == 'kill'
168
- begin
169
- participant.cancel(fei, 'kill')
170
- rescue Exception => e
171
- # intercept anything
172
- nil
173
- end
174
- else
175
- participant.cancel(fei, flavour)
176
- end
167
+ do_persist || return
168
+ #
169
+ # if do_persist returns false, it means we're operating on stale
170
+ # data and have thus to cease
177
171
 
178
- reply_to_parent(h.applied_workitem) if r != false
172
+ @context.storage.put_msg(
173
+ 'dispatch_cancel',
174
+ 'fei' => h.fei,
175
+ 'participant_name' => h.participant_name,
176
+ 'flavour' => flavour,
177
+ 'workitem' => h.applied_workitem)
179
178
  end
180
179
 
181
180
  def reply_to_parent (workitem)
182
181
 
183
182
  workitem['fields'].delete('params')
183
+ workitem['fields'].delete('dispatched_at')
184
184
  super(workitem)
185
185
  end
186
186
 
@@ -344,13 +344,24 @@ module Ruote::Exp
344
344
  #
345
345
  def cancel (flavour)
346
346
 
347
- return reply_to_parent(h.applied_workitem) \
348
- unless h.children.find { |cfei| Ruote::Exp::FlowExpression.fetch(@context, cfei) }
347
+ return reply_to_parent(h.applied_workitem) if h.children.empty?
348
+ #
349
+ # there are no children, nothing to cancel, let's just reply to
350
+ # the parent expression
349
351
 
350
352
  do_persist || return
353
+ #
351
354
  # before firing the cancel message to the children
355
+ #
356
+ # if the do_persist returns false, it means it failed, implying this
357
+ # expression is stale, let's return, thus discarding this cancel message
352
358
 
353
- h.children.each do |cfei|
359
+ children.each do |cfei|
360
+ #
361
+ # let's send a cancel message to each of the children
362
+ #
363
+ # maybe some of them are gone or have not yet been applied, anyway,
364
+ # the message are sent
354
365
 
355
366
  @context.storage.put_msg(
356
367
  'cancel',
@@ -358,6 +369,22 @@ module Ruote::Exp
358
369
  'parent_id' => h.fei, # indicating that this is a "cancel child"
359
370
  'flavour' => flavour)
360
371
  end
372
+
373
+ #if ! children.find { |i| Ruote::Exp::FlowExpression.fetch(@context, i) }
374
+ # #
375
+ # # since none of the children could be found in the storage right now,
376
+ # # it could mean that all children are already done or it could mean
377
+ # # that they are not yet applied...
378
+ # #
379
+ # # just to be sure let's send a new cancel message to this expression
380
+ # #
381
+ # # it's very important, since if there is no child to cancel the parent
382
+ # # the flow might get stuck here
383
+ # @context.storage.put_msg(
384
+ # 'cancel',
385
+ # 'fei' => h.fei,
386
+ # 'flavour' => flavour)
387
+ #end
361
388
  end
362
389
 
363
390
  def do_fail (msg)
@@ -64,7 +64,6 @@ module Ruote::Exp
64
64
 
65
65
  if h.variables
66
66
 
67
- #val = h.variables[var]
68
67
  val = Ruote.lookup(h.variables, var)
69
68
 
70
69
  return val if val != nil
@@ -74,7 +73,8 @@ module Ruote::Exp
74
73
  #
75
74
  # do not lookup variables in a remote engine ...
76
75
 
77
- return parent.lookup_variable(var, prefix)
76
+ (return parent.lookup_variable(var, prefix)) rescue nil
77
+ # if the lookup fails (parent gone) then rescue and let go
78
78
  end
79
79
 
80
80
  @context.storage.get_engine_variable(var)
@@ -242,13 +242,21 @@ module Ruote
242
242
  end
243
243
 
244
244
  action = msg['action'][0, 2]
245
- action = 'rc' if msg['action'] == 'receive'
246
- action = color('4;32', action) if action == 'la'
247
- action = color('4;31', action) if action == 'te'
248
- action = color('31', action) if action == 'ce'
249
- action = color('31', action) if action == 'ca'
250
- action = color('4;33', action) if action == 'rc'
251
- action = color('4;33', action) if action == 'di'
245
+ action = case msg['action']
246
+ when 'receive' then 'rc'
247
+ when 'dispatch_cancel' then 'dc'
248
+ else action
249
+ end
250
+ action = case action
251
+ when 'la' then color('4;32', action)
252
+ when 'te' then color('4;31', action)
253
+ when 'ce' then color('31', action)
254
+ when 'ca' then color('31', action)
255
+ when 'rc' then color('4;33', action)
256
+ when 'dc' then color('4;31', action)
257
+ when 'di' then color('4;33', action)
258
+ else action
259
+ end
252
260
 
253
261
  color(
254
262
  @color,
@@ -39,6 +39,38 @@ module Ruote
39
39
  @context = context
40
40
  end
41
41
 
42
+ def handle (msg)
43
+
44
+ case msg['action']
45
+ when 'dispatch'
46
+ dispatch(msg)
47
+ when 'dispatch_cancel'
48
+ dispatch_cancel(msg)
49
+ else
50
+ # simply discard message
51
+ end
52
+ end
53
+
54
+ protected
55
+
56
+ def dispatch_cancel (msg)
57
+
58
+ flavour = msg['flavour']
59
+
60
+ participant = @context.plist.lookup(msg['participant_name'])
61
+
62
+ begin
63
+ participant.cancel(Ruote::FlowExpressionId.new(msg['fei']), flavour)
64
+ rescue Exception => e
65
+ raise(e) if flavour != 'kill'
66
+ end
67
+
68
+ @context.storage.put_msg(
69
+ 'reply',
70
+ 'fei' => msg['fei'],
71
+ 'workitem' => msg['workitem'])
72
+ end
73
+
42
74
  def dispatch (msg)
43
75
 
44
76
  participant = @context.plist.lookup(msg['participant_name'])
@@ -50,12 +82,12 @@ module Ruote
50
82
  end
51
83
  end
52
84
 
53
- protected
54
-
55
85
  def do_dispatch (participant, msg)
56
86
 
57
87
  workitem = Ruote::Workitem.new(msg['workitem'])
58
88
 
89
+ workitem.fields['dispatched_at'] = Ruote.now_to_utc_s
90
+
59
91
  participant.consume(workitem)
60
92
  end
61
93
 
@@ -116,22 +116,19 @@ module Ruote
116
116
 
117
117
  def get_schedules (delta, now)
118
118
 
119
- if delta < 1.0
120
-
121
- at = now.strftime('%Y%m%d%H%M%S')
122
- get_many('schedules', /-#{at}$/)
123
-
124
- elsif delta < 60.0
125
-
126
- at = now.strftime('%Y%m%d%H%M')
127
- scheds = get_many('schedules', /-#{at}\d\d$/)
128
- filter_schedules(scheds, now)
129
-
130
- else # load all the schedules
131
-
132
- scheds = get_many('schedules')
133
- filter_schedules(scheds, now)
134
- end
119
+ #if delta < 1.0
120
+ # at = now.strftime('%Y%m%d%H%M%S')
121
+ # get_many('schedules', /-#{at}$/)
122
+ #elsif delta < 60.0
123
+ # at = now.strftime('%Y%m%d%H%M')
124
+ # scheds = get_many('schedules', /-#{at}\d\d$/)
125
+ # filter_schedules(scheds, now)
126
+ #else # load all the schedules
127
+
128
+ scheds = get_many('schedules')
129
+ filter_schedules(scheds, now)
130
+
131
+ #end
135
132
  end
136
133
 
137
134
  def put_schedule (flavour, owner_fei, s, msg)
@@ -23,6 +23,6 @@
23
23
  #++
24
24
 
25
25
  module Ruote
26
- VERSION = '2.1.8'
26
+ VERSION = '2.1.9'
27
27
  end
28
28
 
@@ -66,7 +66,7 @@ module Ruote
66
66
 
67
67
  def run_in_thread
68
68
 
69
- Thread.abort_on_exception = true
69
+ #Thread.abort_on_exception = true
70
70
  # TODO : remove me at some point
71
71
 
72
72
  @running = true
@@ -228,10 +228,9 @@ module Ruote
228
228
 
229
229
  Ruote::Exp::FlowExpression.do_action(@context, msg)
230
230
 
231
- elsif action == 'dispatch'
231
+ elsif action.match(/^dispatch/)
232
232
 
233
- #dispatch(msg)
234
- @context.dispatch_pool.dispatch(msg)
233
+ @context.dispatch_pool.handle(msg)
235
234
 
236
235
  elsif PROC_ACTIONS.include?(action)
237
236
 
@@ -108,6 +108,13 @@ module Ruote
108
108
  fields['__result__'] = r
109
109
  end
110
110
 
111
+ # When was this workitem dispatched ?
112
+ #
113
+ def dispatch_at
114
+
115
+ fields['dispatched_at']
116
+ end
117
+
111
118
  # Warning : equality is based on fei and not on payload !
112
119
  #
113
120
  def == (other)
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{ruote}
8
- s.version = "2.1.8"
8
+ s.version = "2.1.9"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["John Mettraux", "Kenneth Kalmer", "Torsten Schoenebaum"]
12
- s.date = %q{2010-03-15}
12
+ s.date = %q{2010-03-23}
13
13
  s.description = %q{
14
14
  ruote is an open source ruby workflow engine.
15
15
  }
@@ -34,6 +34,8 @@ module FunctionalBase
34
34
  @tracer = Tracer.new
35
35
 
36
36
  @engine.add_service('tracer', @tracer)
37
+
38
+ #noisy # uncommented, it makes all the tests noisy
37
39
  end
38
40
 
39
41
  def teardown
@@ -30,7 +30,11 @@ class EftWaitTest < Test::Unit::TestCase
30
30
  assert_trace 'done.', pdef
31
31
 
32
32
  #p [ ts[1].sec, ts[0].sec ]
33
- assert [ 2, 3 ].include?((ts[1].sec - ts[0].sec) % 60)
33
+ d = (ts[1].sec - ts[0].sec) % 60
34
+
35
+ assert(
36
+ [ 2, 3 ].include?(d),
37
+ "delta is #{d}, which isn't 2 or 3")
34
38
  end
35
39
 
36
40
  def test_cancel_wait
@@ -252,7 +252,12 @@ class EftConcurrentIteratorTest < Test::Unit::TestCase
252
252
 
253
253
  #noisy
254
254
 
255
- assert_trace *%w[ a b c ].permutation.to_a, pdef
255
+ #assert_trace(*%w[ a b c ].permutation.to_a, pdef)
256
+ # this is not ruby 1.8.7p72 friendly
257
+
258
+ perms = %w[ a b c ].permutation.to_a
259
+ perms << pdef
260
+ assert_trace(*perms)
256
261
  end
257
262
 
258
263
  def test_merge_type_isolate
@@ -309,7 +314,8 @@ class EftConcurrentIteratorTest < Test::Unit::TestCase
309
314
 
310
315
  def test_cancel
311
316
 
312
- n = 77
317
+ #n = 77
318
+ n = 14
313
319
 
314
320
  pdef = Ruote.process_definition do
315
321
  concurrent_iterator :times => n do
@@ -131,6 +131,7 @@ class EftSetTest < Test::Unit::TestCase
131
131
 
132
132
  @engine.register_participant :alpha do |workitem|
133
133
  workitem.fields.delete('params')
134
+ workitem.fields.delete('dispatched_at')
134
135
  @tracer << workitem.fields.inspect
135
136
  end
136
137
 
@@ -182,7 +182,10 @@ class EftConcurrenceTest < Test::Unit::TestCase
182
182
 
183
183
  wi = run_concurrence({ :merge_type => :isolate }, false)
184
184
 
185
- assert_equal(%w[ 0 1 params ], wi.fields.keys.collect { |k| k.to_s }.sort)
185
+ assert_equal(
186
+ %w[ 0 1 dispatched_at params ],
187
+ wi.fields.keys.collect { |k| k.to_s }.sort)
188
+
186
189
  assert_equal({ 'ref' => 'alpha' }, wi.fields['params'])
187
190
  assert_equal(%w[ seen ], wi.fields['0'].keys)
188
191
  assert_equal(%w[ seen ], wi.fields['1'].keys)
@@ -193,7 +196,7 @@ class EftConcurrenceTest < Test::Unit::TestCase
193
196
  wi = run_concurrence({ :merge_type => :stack }, false)
194
197
 
195
198
  assert_equal(
196
- %w[ params stack stack_attributes ],
199
+ %w[ dispatched_at params stack stack_attributes ],
197
200
  wi.fields.keys.collect { |k| k.to_s }.sort)
198
201
 
199
202
  assert_equal({ 'ref' => 'alpha' }, wi.fields['params'])
@@ -230,6 +233,8 @@ class EftConcurrenceTest < Test::Unit::TestCase
230
233
 
231
234
  def test_count
232
235
 
236
+ #noisy
237
+
233
238
  wfid = run_test_count('cancel', false)
234
239
 
235
240
  #puts
@@ -237,6 +242,8 @@ class EftConcurrenceTest < Test::Unit::TestCase
237
242
  #puts
238
243
  assert_equal 1, logger.log.select { |e| e['action'] == 'cancel' }.size
239
244
 
245
+ sleep 0.350 # since now dispatch_cancel occurs asynchronously...
246
+
240
247
  assert_equal 0, @alpha.size
241
248
  assert_equal 0, @bravo.size
242
249
  end
@@ -31,6 +31,8 @@ class FtLaunchitemTest < Test::Unit::TestCase
31
31
  wait_for(wfid)
32
32
 
33
33
  assert_equal('a', @tracer.to_s)
34
+
35
+ assert_not_nil(fields.delete('dispatched_at'))
34
36
  assert_equal({"a"=>0, "b"=>1, "params"=>{"ref"=>"alpha"}}, fields)
35
37
  end
36
38
  end
@@ -22,7 +22,6 @@ class FtReApplyTest < Test::Unit::TestCase
22
22
 
23
23
  def test_re_apply
24
24
 
25
-
26
25
  alpha = @engine.register_participant :alpha, Ruote::HashParticipant.new
27
26
 
28
27
  #noisy
@@ -32,7 +32,7 @@ class FtTimeoutTest < Test::Unit::TestCase
32
32
 
33
33
  assert_equal 0, alpha.size
34
34
  assert_equal 1, bravo.size
35
- assert_equal 1, logger.log.select { |e| e['flavour'] == 'timeout' }.size
35
+ assert_equal 2, logger.log.select { |e| e['flavour'] == 'timeout' }.size
36
36
  assert_equal 0, @engine.storage.get_many('schedules').size
37
37
 
38
38
  assert_not_nil bravo.first.fields['__timed_out__']
@@ -68,6 +68,16 @@ class FtTimeoutTest < Test::Unit::TestCase
68
68
 
69
69
  def test_on_timeout_redo
70
70
 
71
+ # with ruote-couch the 'cancel-process' operation gets overriden by
72
+ # the timeout cancel...
73
+ #
74
+ # 0 20 ca * 20100320-bipopimita {}
75
+ # 1 20 ca * 20100320-bipopimita 0 {"flavour"=>nil}
76
+ # 2 20 ca * 20100320-bipopimita 0_0 {"flavour"=>"timeout"}
77
+ # 3 20 ca * 20100320-bipopimita 0_0 {"flavour"=>nil, :pi=>"0!!20100320-bipopimita"}
78
+ #
79
+ # hence the multiple cancel at the end of the test
80
+
71
81
  pdef = Ruote.process_definition do
72
82
  alpha :timeout => '1.1', :on_timeout => 'redo'
73
83
  end
@@ -82,7 +92,10 @@ class FtTimeoutTest < Test::Unit::TestCase
82
92
  #logger.log.each { |e| p e['flavour'] }
83
93
  assert logger.log.select { |e| e['flavour'] == 'timeout' }.size >= 2
84
94
 
85
- @engine.cancel_process(wfid)
95
+ 3.times do
96
+ Thread.pass
97
+ @engine.cancel_process(wfid)
98
+ end
86
99
 
87
100
  wait_for(wfid)
88
101
 
@@ -195,7 +208,8 @@ class FtTimeoutTest < Test::Unit::TestCase
195
208
 
196
209
  wfid = @engine.launch(pdef)
197
210
 
198
- wait_for(9)
211
+ #wait_for(9)
212
+ wait_for(wfid)
199
213
 
200
214
  assert_nil @engine.process(wfid)
201
215
  assert_equal 0, alpha.size
@@ -84,6 +84,27 @@ class FtProcessStatusTest < Test::Unit::TestCase
84
84
  ps.variables)
85
85
  end
86
86
 
87
+ def test_errors
88
+
89
+ pdef = Ruote.process_definition 'my process' do
90
+ nada
91
+ end
92
+
93
+ wfid = @engine.launch( pdef )
94
+ wait_for( wfid )
95
+
96
+ errs = @engine.errors
97
+
98
+ assert_equal 1, errs.size
99
+
100
+ assert_equal wfid, errs.first['fei']['wfid']
101
+
102
+ err = @engine.errors( wfid )
103
+
104
+ assert_equal 1, err.size
105
+ assert_equal wfid, err.first['fei']['wfid']
106
+ end
107
+
87
108
  def test_tree
88
109
 
89
110
  pdef = Ruote.process_definition 'my process' do
@@ -34,13 +34,13 @@ class FtParticipantTimeoutTest < Test::Unit::TestCase
34
34
  #noisy
35
35
 
36
36
  wfid = @engine.launch(pdef)
37
- wait_for(10)
37
+ wait_for(12)
38
38
 
39
39
  assert_equal 0, alpha.size
40
40
  assert_equal 1, bravo.size
41
41
 
42
42
  #logger.log.each { |l| p l }
43
- assert_equal 1, logger.log.select { |e| e['flavour'] == 'timeout' }.size
43
+ assert_equal 2, logger.log.select { |e| e['flavour'] == 'timeout' }.size
44
44
  assert_equal 0, @engine.storage.get_many('schedules').size
45
45
 
46
46
  assert_not_nil bravo.first.fields['__timed_out__']
@@ -164,6 +164,8 @@ class FtEngineParticipantTest < Test::Unit::TestCase
164
164
  @engine0.cancel_process(wfid)
165
165
  @engine0.wait_for(wfid)
166
166
 
167
+ sleep 0.350 # since dispatch_cancel is asyncrhonous now
168
+
167
169
  assert_equal 0, alpha.size
168
170
 
169
171
  assert_equal "a", @tracer0.to_s
@@ -71,5 +71,23 @@ class FtParticipantConsumptionTest < Test::Unit::TestCase
71
71
 
72
72
  assert_trace('alpha 0_0_0', pdef)
73
73
  end
74
+
75
+ def test_dispatch_time
76
+
77
+ wis = []
78
+
79
+ pdef = Ruote.process_definition { alpha; alpha }
80
+
81
+ @engine.register_participant 'alpha' do |workitem|
82
+ wis << workitem.to_h.dup
83
+ end
84
+
85
+ assert_trace('', pdef)
86
+
87
+ assert_equal(
88
+ String, wis.first['fields']['dispatched_at'].class)
89
+ assert_not_equal(
90
+ wis.first['fields']['dispathed_at'], wis.last['fields']['dispatched_at'])
91
+ end
74
92
  end
75
93
 
@@ -8,6 +8,7 @@
8
8
  # making sure the tests see ruote
9
9
 
10
10
  puts `ruby -v`
11
+ puts Time.now.to_s
11
12
 
12
13
  ruotelib = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
13
14
  $:.unshift(ruotelib) unless $:.include?(ruotelib)
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 2
7
7
  - 1
8
- - 8
9
- version: 2.1.8
8
+ - 9
9
+ version: 2.1.9
10
10
  platform: ruby
11
11
  authors:
12
12
  - John Mettraux
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2010-03-15 00:00:00 +09:00
19
+ date: 2010-03-23 00:00:00 +09:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency