ruote 2.1.4 → 2.1.5

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