ruote 2.1.4 → 2.1.5

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.txt CHANGED
@@ -1,7 +1,27 @@
1
1
 
2
2
  = ruote - CHANGELOG.txt
3
3
 
4
- == ruote - 2.1.4 released 2010/01/11
4
+
5
+ == ruote - 2.1.5 released 2010/01/28
6
+
7
+ - fixed StorageParticipant a to b flow, fix by Torsten
8
+ - fixed StorageParticipant#cancel
9
+ - dollar : made sure of ${fei} and ${wfid}
10
+ - implemented ProcessStatus#to_dot
11
+ - if a participant implementation cancel method returns false,
12
+ reply_to_parent will not get called
13
+ - changes about errors without [stored] expressions, they now appear in process
14
+ statuses
15
+ - EngineParticipant implemented
16
+ - 'ruby_eval_allowed' instead of :ruby_eval_allowed
17
+ - ${v:customer.address.1} deep trick now ok (as it was ok for fields)
18
+ - added d() to the $ notation : echo "${r: d('f:toto') }"
19
+ - Engine#kill_process(wfid) can cure errored participant expressions
20
+ - made sure ${r:wi} and ${r:workitem} is and instance of Ruote::Workitem
21
+ - implemented StorageParticipant#by_field
22
+
23
+
24
+ == ruote - 2.1.4 released 2010/01/11
5
25
 
6
26
  - implemented StorageHistory
7
27
  - using yyyy-mm-dd instead of yyyy/mm/dd for Ruote.time_to_utc_s(t)
@@ -9,19 +29,19 @@
9
29
  - Engine#add_service now returning just bound service
10
30
 
11
31
 
12
- == ruote - 2.1.3 released 2010/01/04
32
+ == ruote - 2.1.3 released 2010/01/04
13
33
 
14
34
  - fixed issue with Rufus.is_cron_string (thanks Torsten)
15
35
  - fixed issue with FlowExpression#cancel (Kenneth)
16
36
 
17
37
 
18
- == ruote - 2.1.2 released 2010/01/03
38
+ == ruote - 2.1.2 released 2010/01/03
19
39
 
20
40
  - fixed issue when initializing engine without worker. Thanks Matt Nichols.
21
41
 
22
42
 
23
- == ruote - 2.1.1 released 2009/12/31
43
+ == ruote - 2.1.1 released 2009/12/31
24
44
 
25
- == OpenWFEru - 0.9.2 released 2007/01/26
26
- == openwfe-ruby - 1.7.0 released 2006/05/08
45
+ == OpenWFEru - 0.9.2 released 2007/01/26
46
+ == openwfe-ruby - 1.7.0 released 2006/05/08
27
47
 
data/CREDITS.txt CHANGED
@@ -15,12 +15,12 @@ Kenneth Kalmer http://www.opensourcery.co.za
15
15
  Contributors
16
16
  ------------
17
17
 
18
+ Torsten Schoenebaum - ActiveResourceParticipant and much more
18
19
  Matt Nichols - http://github.com/mattnichols
19
20
  Nicholas Faiz - http://github.com/biv
20
21
  Chris Beer - http://github.com/cbeer
21
22
  Enrico Bianco - http://github.com/enricob
22
23
  Andrew Timberlake - timeout 'at'
23
- Torsten Schoenebaum - ActiveResourceParticipant and more
24
24
  Raphael Simon - error handling mechanism design and QA
25
25
  Maarten Oelering - bug reports and test cases
26
26
  Nick Petrella - socket listener issues and Python interactivity, dollar patch
data/TODO.txt CHANGED
@@ -171,6 +171,19 @@
171
171
  [o] maybe cancel should have a safely / redo_reply thing
172
172
  [o] implement Storage#clear!(type)
173
173
  [o] ruote/util/time.rb utc_to_s 'YYYY/MM/DD' --> 'YYYY-MM-DD' (regex friendly)
174
+ [x] store participant bytecode/AST ?
175
+ [o] ${r:puts(d("f:nada"))}
176
+ [o] :ruby_eval_allowed vs 'ruby_eval_allowed'
177
+ [o] check : what if a reply on a concurrence wants to save, whereas the
178
+ concurrence terminated (got removed) meanwhile ?
179
+ the reply returns true...
180
+ [o] implement StorageHistory
181
+ [x] nuke FsHistory ? keep
182
+ [o] EngineParticipant
183
+ [x] expstorage.to_dot
184
+ [o] process_status.to_dot
185
+ [o] EngineParticipant : don't wait in case of forget (reply could NEVER come !)
186
+ [x] align :forget behaviour on EngineParticipant forget... OK as it is
174
187
 
175
188
  [ ] exp : exp (restricted form of eval ?)
176
189
  [ ] exp : case (is it necessary ?)
@@ -197,8 +210,6 @@
197
210
 
198
211
  [ ] participant dispatch thread throttling ?
199
212
 
200
- [ ] expstorage.to_dot
201
-
202
213
  [ ] tailcall
203
214
  [ ] subprocesses participants (alias ?)
204
215
 
@@ -277,15 +288,15 @@
277
288
  [ ] at expression ?
278
289
  [ ] listen to participants/errors/tags {in|out}
279
290
 
280
- [ ] implement StorageHistory
281
- [ ] nuke FsHistory ?
282
-
283
291
  [ ] remove abort_on_exception=true
284
292
 
285
- [ ] check : what if a reply on a concurrence wants to save, whereas the
286
- concurrence terminated (got removed) meanwhile ?
287
- the reply returns true...
288
-
289
293
  [ ] shell ? irb ? Shell.new(storage)
290
294
  [ ] focus on fulldup or json.dup (via fulldup ?)
291
295
 
296
+ [ ] ruote-dm 2.1
297
+
298
+ [ ] implement pause engine
299
+ [ ] implement pause process
300
+
301
+ [ ] engine.on_error = 'participant_name'
302
+
@@ -9,8 +9,9 @@ require 'ruote/storage/fs_storage'
9
9
 
10
10
  engine = Ruote::Engine.new(
11
11
  Ruote::Worker.new(
12
- Ruote::FsStorage.new("ruote_work")))
13
- #Ruote::HashStorage.new))
12
+ Ruote::FsStorage.new(
13
+ 'ruote_work',
14
+ 's_logger' => [ 'ruote/log/test_logger', 'Ruote::TestLogger' ])))
14
15
 
15
16
  # registering participants
16
17
 
data/lib/ruote.rb CHANGED
@@ -2,5 +2,6 @@
2
2
  require 'ruote/storage/hash_storage'
3
3
  require 'ruote/worker'
4
4
  require 'ruote/engine'
5
+ require 'ruote/participant'
5
6
  require 'ruote/parser/ruby_dsl'
6
7
 
data/lib/ruote/context.rb CHANGED
@@ -52,6 +52,11 @@ module Ruote
52
52
  initialize_services
53
53
  end
54
54
 
55
+ def engine_id
56
+
57
+ @conf['engine_id'] || 'engine'
58
+ end
59
+
55
60
  def [] (key)
56
61
 
57
62
  @conf[key]
data/lib/ruote/engine.rb CHANGED
@@ -113,14 +113,7 @@ module Ruote
113
113
  exp.unpersist_or_raise if exp
114
114
  end
115
115
 
116
- #@storage.delete(err.to_h) # remove error
117
- #
118
- # done when the expression gets deleted
119
- #
120
- # but
121
- #
122
- # is there a case, 5 lines above, where there is no expression
123
- # to delete ?
116
+ @storage.delete(err.to_h) # remove error
124
117
 
125
118
  @storage.put_msg(action, msg) # trigger replay
126
119
  end
@@ -141,12 +134,12 @@ module Ruote
141
134
  #
142
135
  def process (wfid)
143
136
 
144
- exps = @storage.get_many('expressions', /#{wfid}$/)
137
+ exps = @storage.get_many('expressions', /!#{wfid}$/)
138
+ errs = @storage.get_many('errors', /!#{wfid}$/)
145
139
 
146
- return nil if exps.size < 1
140
+ return nil if exps.empty? && errs.empty?
147
141
 
148
- ProcessStatus.new(
149
- @context, exps, @storage.get_many('errors', /#{wfid}$/))
142
+ ProcessStatus.new(@context, exps, errs)
150
143
  end
151
144
 
152
145
  # Returns an array of ProcessStatus instances.
@@ -68,6 +68,19 @@ module Ruote
68
68
  def to_h
69
69
  @h
70
70
  end
71
+
72
+ protected
73
+
74
+ def to_dot (opts)
75
+
76
+ i = fei.to_storage_id
77
+ label = "error : #{message.gsub(/"/, "'")}"
78
+
79
+ [
80
+ "\"err_#{i}\" [ label = \"#{label}\" ];",
81
+ "\"err_#{i}\" -> \"#{i}\" [ style = \"dotted\" ];"
82
+ ]
83
+ end
71
84
  end
72
85
  end
73
86
 
@@ -47,9 +47,11 @@ module Ruote
47
47
 
48
48
  @expressions = expressions.collect { |e|
49
49
  Ruote::Exp::FlowExpression.from_h(context, e) }
50
+ @expressions.sort! { |a, b| a.fei.expid <=> b.fei.expid }
50
51
 
51
52
  @errors = errors.collect { |e|
52
53
  ProcessError.new(e) }
54
+ @errors.sort! { |a, b| a.fei.expid <=> b.fei.expid }
53
55
  end
54
56
 
55
57
  # Returns the expression at the root of the process instance.
@@ -100,7 +102,11 @@ module Ruote
100
102
  #
101
103
  def wfid
102
104
 
103
- root_expression.fei.wfid
105
+ begin
106
+ root_expression.fei.wfid
107
+ rescue
108
+ @errors.first.fei.wfid
109
+ end
104
110
  end
105
111
 
106
112
  def definition_name
@@ -144,12 +150,23 @@ module Ruote
144
150
  end
145
151
  s << " errors : #{@errors.size}\n"
146
152
  @errors.each do |e|
153
+ s << " #{e.fei.to_storage_id} :\n" if e.fei
147
154
  s << " #{e.inspect}\n"
148
155
  end
149
156
 
150
157
  s
151
158
  end
152
159
 
160
+ def to_dot (opts={})
161
+
162
+ s = [ "digraph \"process wfid #{wfid}\" {" ]
163
+ @expressions.each { |e| s.push(*e.send(:to_dot, opts)) }
164
+ @errors.each { |e| s.push(*e.send(:to_dot, opts)) }
165
+ s << "}"
166
+
167
+ s.join("\n")
168
+ end
169
+
153
170
  def to_h
154
171
 
155
172
  h = {}
@@ -73,11 +73,6 @@ module Ruote::Exp
73
73
  s ? s.to_s.gsub('&amp;', '&').gsub('&gt;', '>').gsub('&lt;', '<') : nil
74
74
  end
75
75
 
76
- #def self.ruby_eval (s)
77
- # treechecker.check_conditional(s)
78
- # eval(s)
79
- #end
80
-
81
76
  def self.to_b (o)
82
77
 
83
78
  o = o.strip if o.is_a?(String)
@@ -162,14 +162,20 @@ module Ruote::Exp
162
162
 
163
163
  def cancel (flavour)
164
164
 
165
- # TODO : if flavour is 'kill', why not not trigger participant.cancel ?
166
-
167
165
  participant = @context.plist.lookup(h.participant_name)
168
- participant.cancel(fei, flavour)
169
- # TODO should this be threaded ?
170
- # TODO should errors be intercepted here ?
171
166
 
172
- reply_to_parent(h.applied_workitem)
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
177
+
178
+ reply_to_parent(h.applied_workitem) if r != false
173
179
  end
174
180
 
175
181
  def reply_to_parent (workitem)
@@ -22,6 +22,8 @@
22
22
  # Made in Japan.
23
23
  #++
24
24
 
25
+ require 'ruote/subprocess'
26
+
25
27
 
26
28
  module Ruote::Exp
27
29
 
@@ -116,7 +118,7 @@ module Ruote::Exp
116
118
  #
117
119
  # subprocess :ref => 'http://pdefs.example.org/account/def1.xml'
118
120
  #
119
- # Remember that the :remote_definition_allowed option of the engine has
121
+ # Remember that the 'remote_definition_allowed' option of the engine has
120
122
  # to be set to true for the latter to work, else the engine will refuse
121
123
  # to load definitions over HTTP.
122
124
  #
@@ -155,7 +157,7 @@ module Ruote::Exp
155
157
 
156
158
  raise "no subprocess referred in #{tree}" unless ref
157
159
 
158
- pos, subtree = lookup_subprocess(ref)
160
+ pos, subtree = Ruote.lookup_subprocess(self, ref)
159
161
 
160
162
  vars = compile_atts
161
163
  vars.merge!('tree' => tree_children.first)
@@ -163,41 +165,6 @@ module Ruote::Exp
163
165
 
164
166
  launch_sub(pos, subtree, :variables => vars)
165
167
  end
166
-
167
- protected
168
-
169
- def lookup_subprocess (ref)
170
-
171
- val = lookup_variable(ref)
172
-
173
- # a classical subprocess stored in a variable ?
174
-
175
- return [ '0', val ] if is_tree?(val)
176
- return val if is_pos_tree?(val)
177
-
178
- # maybe subprocess :ref => 'uri'
179
-
180
- subtree = @context.parser.parse(ref) rescue nil
181
-
182
- _, subtree = Ruote::Exp::DefineExpression.reorganize(subtree) \
183
- if subtree && Ruote::Exp::DefineExpression.is_definition?(subtree)
184
-
185
- return [ '0', subtree ] if is_tree?(subtree)
186
-
187
- # no luck ...
188
-
189
- raise "no subprocess named '#{ref}' found"
190
- end
191
-
192
- def is_tree? (a)
193
-
194
- a.is_a?(Array) && a[1].is_a?(Hash) && a.size == 3
195
- end
196
-
197
- def is_pos_tree? (a)
198
-
199
- a.is_a?(Array) && a.size == 2 && a[0].is_a?(String) && is_tree?(a[1])
200
- end
201
168
  end
202
169
  end
203
170
 
@@ -133,7 +133,7 @@ module Ruote::Exp
133
133
  #
134
134
  # == ${ruby:'hello'}
135
135
  #
136
- # Remember that, if the engine's :ruby_eval_allowed is set to true, the
136
+ # Remember that, if the engine's 'ruby_eval_allowed' is set to true, the
137
137
  # condition may contain Ruby code.
138
138
  #
139
139
  # _when '${r:"hell" + "o"} == hello'
@@ -145,6 +145,21 @@ module Ruote::Exp
145
145
 
146
146
  def self.do_action (context, msg)
147
147
 
148
+ fei = msg['fei']
149
+ action = msg['action']
150
+
151
+ if action == 'reply' && fei['engine_id'] != context.engine_id
152
+
153
+ ep = context.plist.lookup(fei['engine_id'])
154
+
155
+ raise(
156
+ "no EngineParticipant found under name '#{fei['engine_id']}'"
157
+ ) unless ep
158
+
159
+ ep.reply(fei, msg['workitem'])
160
+ return
161
+ end
162
+
148
163
  fexp = nil
149
164
 
150
165
  3.times do
@@ -154,7 +169,7 @@ module Ruote::Exp
154
169
  end
155
170
  # this retry system is only useful with ruote-couch
156
171
 
157
- fexp.send("do_#{msg['action']}", msg) if fexp
172
+ fexp.send("do_#{action}", msg) if fexp
158
173
  end
159
174
 
160
175
  def do_apply
@@ -184,15 +199,6 @@ module Ruote::Exp
184
199
 
185
200
  def reply_to_parent (workitem, delete=true)
186
201
 
187
- #if delete && h.state.nil?
188
- # p @msg
189
- # if @msg && @msg['action'] == 'reply'
190
- # do_unpersist || return
191
- # else
192
- # unpersist_or_raise
193
- # end
194
- #end
195
-
196
202
  if h.tagname
197
203
 
198
204
  unset_variable(h.tagname)
@@ -291,16 +297,16 @@ module Ruote::Exp
291
297
  #
292
298
  def do_cancel (msg)
293
299
 
294
- return if h.state == 'cancelling'
295
- # cancel on cancel gets discarded
296
-
297
- @msg = Ruote.fulldup(msg)
298
-
299
300
  flavour = msg['flavour']
300
301
 
302
+ return if h.state == 'cancelling' && flavour != 'kill'
303
+ # cancel on cancel gets discarded
304
+
301
305
  return if h.state == 'failed' && flavour == 'timeout'
302
306
  # do not timeout expressions that are "in error" (failed)
303
307
 
308
+ @msg = Ruote.fulldup(msg)
309
+
304
310
  h.state = case flavour
305
311
  when 'kill' then 'dying'
306
312
  when 'timeout' then 'timing_out'
@@ -490,8 +496,46 @@ module Ruote::Exp
490
496
  tree[2]
491
497
  end
492
498
 
499
+ # Generates a sub_wfid, without hitting storage.
500
+ #
501
+ # There's a better implementation for sure...
502
+ #
503
+ def get_next_sub_wfid
504
+
505
+ i = [
506
+ $$, Time.now.to_f.to_s, self.hash.to_s, @h['fei'].inspect
507
+ ].join('-').hash
508
+
509
+ (i < 0 ? "1#{i * -1}" : "0#{i}").to_s
510
+ end
511
+
493
512
  protected
494
513
 
514
+ def to_dot (opts)
515
+
516
+ i = fei()
517
+
518
+ label = "#{[ i.wfid, i.sub_wfid, i.expid].join(" ")} #{tree.first}"
519
+ label += " (#{h.state})" if h.state
520
+
521
+ a = []
522
+ a << "\"#{i.to_storage_id}\" [ label=\"#{label}\" ];"
523
+
524
+ # parent
525
+
526
+ if h.parent_id
527
+ a << "\"#{i.to_storage_id}\" -> \"#{parent_id.to_storage_id}\";"
528
+ end
529
+
530
+ # children
531
+
532
+ h.children.each do |cfei|
533
+ a << "\"#{i.to_storage_id}\" -> \"#{Ruote.to_storage_id(cfei)}\";"
534
+ end
535
+
536
+ a
537
+ end
538
+
495
539
  def pre_apply_child (child_index, workitem, forget)
496
540
 
497
541
  child_fei = h.fei.merge('expid' => "#{h.fei['expid']}_#{child_index}")
@@ -519,19 +563,6 @@ module Ruote::Exp
519
563
  @context.storage.put_msg('apply', msg)
520
564
  end
521
565
 
522
- # Generates a sub_wfid, without hitting storage.
523
- #
524
- # There's a better implementation for sure...
525
- #
526
- def get_next_sub_wfid
527
-
528
- i = [
529
- $$, Time.now.to_f.to_s, self.hash.to_s, @h['fei'].inspect
530
- ].join('-').hash
531
-
532
- (i < 0 ? "1#{i * -1}" : "0#{i}").to_s
533
- end
534
-
535
566
  def register_child (fei)
536
567
 
537
568
  h.children << fei