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 +26 -6
- data/CREDITS.txt +1 -1
- data/TODO.txt +20 -9
- data/examples/ruote_quickstart.rb +3 -2
- data/lib/ruote.rb +1 -0
- data/lib/ruote/context.rb +5 -0
- data/lib/ruote/engine.rb +5 -12
- data/lib/ruote/engine/process_error.rb +13 -0
- data/lib/ruote/engine/process_status.rb +18 -1
- data/lib/ruote/exp/condition.rb +0 -5
- data/lib/ruote/exp/fe_participant.rb +12 -6
- data/lib/ruote/exp/fe_subprocess.rb +4 -37
- data/lib/ruote/exp/fe_when.rb +1 -1
- data/lib/ruote/exp/flowexpression.rb +59 -28
- data/lib/ruote/exp/ro_persist.rb +4 -7
- data/lib/ruote/exp/ro_variables.rb +6 -2
- data/lib/ruote/fei.rb +9 -0
- data/lib/ruote/log/wait_logger.rb +1 -0
- data/lib/ruote/part/engine_participant.rb +185 -0
- data/lib/ruote/part/storage_participant.rb +69 -13
- data/lib/ruote/participant.rb +1 -0
- data/lib/ruote/storage/base.rb +1 -1
- data/lib/ruote/subprocess.rb +68 -0
- data/lib/ruote/util/dollar.rb +23 -5
- data/lib/ruote/worker.rb +30 -9
- data/ruote.gemspec +5 -2
- data/test/functional/eft_27_inc.rb +6 -6
- data/test/functional/ft_10_dollar.rb +84 -1
- data/test/functional/ft_1_process_status.rb +43 -0
- data/test/functional/ft_20_storage_participant.rb +124 -5
- data/test/functional/ft_2_errors.rb +11 -4
- data/test/functional/ft_37_engine_participant.rb +295 -0
- metadata +5 -2
data/CHANGELOG.txt
CHANGED
@@ -1,7 +1,27 @@
|
|
1
1
|
|
2
2
|
= ruote - CHANGELOG.txt
|
3
3
|
|
4
|
-
|
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
|
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
|
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
|
43
|
+
== ruote - 2.1.1 released 2009/12/31
|
24
44
|
|
25
|
-
== OpenWFEru - 0.9.2
|
26
|
-
== openwfe-ruby - 1.7.0
|
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(
|
13
|
-
|
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
data/lib/ruote/context.rb
CHANGED
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
|
-
|
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',
|
137
|
+
exps = @storage.get_many('expressions', /!#{wfid}$/)
|
138
|
+
errs = @storage.get_many('errors', /!#{wfid}$/)
|
145
139
|
|
146
|
-
return nil if exps.
|
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
|
-
|
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 = {}
|
data/lib/ruote/exp/condition.rb
CHANGED
@@ -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
|
-
|
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
|
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
|
|
data/lib/ruote/exp/fe_when.rb
CHANGED
@@ -133,7 +133,7 @@ module Ruote::Exp
|
|
133
133
|
#
|
134
134
|
# == ${ruby:'hello'}
|
135
135
|
#
|
136
|
-
# Remember that, if the engine's
|
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_#{
|
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
|