ruote 2.1.8 → 2.1.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -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