ruote 2.1.9 → 2.1.10
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 +32 -0
- data/CREDITS.txt +3 -0
- data/Rakefile +4 -4
- data/TODO.txt +55 -11
- data/examples/barley.rb +2 -1
- data/examples/flickr_report.rb +5 -6
- data/examples/web_first_page.rb +11 -0
- data/lib/ruote/context.rb +36 -13
- data/lib/ruote/engine.rb +88 -56
- data/lib/ruote/engine/process_error.rb +13 -0
- data/lib/ruote/engine/process_status.rb +33 -1
- data/lib/ruote/error_handler.rb +122 -0
- data/lib/ruote/evt/tracker.rb +27 -10
- data/lib/ruote/exp/fe_apply.rb +69 -0
- data/lib/ruote/exp/fe_participant.rb +33 -5
- data/lib/ruote/exp/flowexpression.rb +37 -5
- data/lib/ruote/exp/ro_persist.rb +8 -4
- data/lib/ruote/exp/ro_variables.rb +2 -2
- data/lib/ruote/fei.rb +59 -7
- data/lib/ruote/log/storage_history.rb +2 -0
- data/lib/ruote/log/test_logger.rb +28 -19
- data/lib/ruote/log/wait_logger.rb +4 -2
- data/lib/ruote/parser.rb +2 -1
- data/lib/ruote/part/dispatch_pool.rb +10 -10
- data/lib/ruote/part/engine_participant.rb +2 -2
- data/lib/ruote/part/local_participant.rb +99 -7
- data/lib/ruote/part/participant_list.rb +18 -7
- data/lib/ruote/part/storage_participant.rb +9 -6
- data/lib/ruote/receiver/base.rb +109 -10
- data/lib/ruote/storage/base.rb +118 -41
- data/lib/ruote/storage/fs_storage.rb +1 -0
- data/lib/ruote/storage/hash_storage.rb +2 -1
- data/lib/ruote/util/lookup.rb +22 -2
- data/lib/ruote/util/misc.rb +5 -5
- data/lib/ruote/version.rb +1 -1
- data/lib/ruote/worker.rb +50 -63
- data/lib/ruote/workitem.rb +64 -0
- data/ruote.gemspec +17 -12
- data/test/functional/base.rb +3 -1
- data/test/functional/concurrent_base.rb +35 -29
- data/test/functional/crunner.sh +19 -0
- data/test/functional/ct_0_concurrence.rb +17 -30
- data/test/functional/ct_1_iterator.rb +20 -17
- data/test/functional/ct_2_cancel.rb +32 -25
- data/test/functional/eft_12_listen.rb +2 -1
- data/test/functional/eft_23_apply.rb +23 -0
- data/test/functional/eft_3_participant.rb +27 -0
- data/test/functional/ft_11_recursion.rb +1 -1
- data/test/functional/ft_13_variables.rb +22 -0
- data/test/functional/ft_14_re_apply.rb +3 -0
- data/test/functional/ft_15_timeout.rb +1 -0
- data/test/functional/ft_20_storage_participant.rb +20 -2
- data/test/functional/ft_21_forget.rb +30 -0
- data/test/functional/ft_22_process_definitions.rb +2 -1
- data/test/functional/ft_24_block_participants.rb +1 -1
- data/test/functional/ft_25_receiver.rb +83 -1
- data/test/functional/ft_26_participant_timeout.rb +1 -1
- data/test/functional/ft_2_errors.rb +2 -5
- data/test/functional/ft_30_smtp_participant.rb +47 -45
- data/test/functional/ft_36_storage_history.rb +4 -4
- data/test/functional/ft_37_engine_participant.rb +14 -10
- data/test/functional/ft_38_participant_more.rb +178 -0
- data/test/functional/ft_39_wait_for.rb +100 -0
- data/test/functional/ft_40_participant_on_reply.rb +87 -0
- data/test/functional/ft_41_participants.rb +65 -0
- data/test/functional/ft_42_storage_copy.rb +67 -0
- data/test/functional/ft_5_on_error.rb +103 -0
- data/test/functional/ft_9_subprocesses.rb +2 -1
- data/test/functional/storage_helper.rb +5 -1
- data/test/functional/test.rb +4 -1
- data/test/functional/vertical.rb +46 -0
- data/test/unit/storage.rb +17 -1
- data/test/unit/storages.rb +27 -7
- data/test/unit/ut_11_lookup.rb +36 -0
- data/test/unit/ut_16_parser.rb +43 -0
- data/test/unit/ut_1_fei.rb +28 -1
- data/test/unit/ut_7_workitem.rb +23 -0
- metadata +67 -105
- data/lib/ruote/log/fs_history.rb +0 -182
- data/test/functional/ft_32_fs_history.rb +0 -188
- data/test/mpc_test.rb +0 -29
data/CHANGELOG.txt
CHANGED
@@ -2,6 +2,38 @@
|
|
2
2
|
= ruote - CHANGELOG.txt
|
3
3
|
|
4
4
|
|
5
|
+
== ruote - 2.1.10 released 2010/06/15
|
6
|
+
|
7
|
+
- storage#copy_to(other_storage) implemented
|
8
|
+
- #launch moved from Engine to ReceiverMixin
|
9
|
+
- participants without initialize(opts) are now allowed
|
10
|
+
- engine.wait_for(:inactive)
|
11
|
+
- engine.wait_for(*interests) unlocked
|
12
|
+
- engine.wait_for(:empty)
|
13
|
+
- fixed issue with participant 'x' and :on_error. Thanks Oleg.
|
14
|
+
- receiver : reply and reply_to_engine : from aliases to wrappers
|
15
|
+
- Ruote::StorageParticipant more flexibility for method args
|
16
|
+
- Ruote::FlowExpressionId .extract_h and .extract
|
17
|
+
- dropped fs_history (storage_history is better)
|
18
|
+
- parser to_xml _if 'x == b' --> <if test="x == b">
|
19
|
+
- workitem.sid shortcut for workitem.fei.to_storage_id
|
20
|
+
- workitem.wfid shorcut for workitem.fei.wfid
|
21
|
+
- new error_handler service
|
22
|
+
- Receiver.new(x), x can be worker, engine, context or storage
|
23
|
+
- Participant#on_reply(workitem) manipulating workitems when they come back
|
24
|
+
- set '${v:customers.0.name}' => 'x' now OK, was limited to fields. Thanks Oleg
|
25
|
+
- LocalParticipant#put(fei, hash) #get(fei, key) for stashing info
|
26
|
+
- LocalParticipant#re_dispatch(wi, opts)
|
27
|
+
- bug in HashStorage, apply over apply didn't raise a persist error. Fixed.
|
28
|
+
- keeping track of workitem fields as they were right before a participant error
|
29
|
+
- Workitem.error holds the error when on_error. Thanks Oleg.
|
30
|
+
- Workitem#error and Workitem#timed_out shortcuts
|
31
|
+
- participant :on_error => 'x' broken. Fixed. Thanks Oleg.
|
32
|
+
- Engine#workitem(fei) for advanced users
|
33
|
+
- LocalParticpant : added a reject(workitem) method
|
34
|
+
- participant exp : dispatched = true set right after dispatch
|
35
|
+
|
36
|
+
|
5
37
|
== ruote - 2.1.9 released 2010/03/22
|
6
38
|
|
7
39
|
- made participant.cancel occur asynchronously (as should be)
|
data/CREDITS.txt
CHANGED
@@ -16,6 +16,7 @@ Torsten Schoenebaum - http://github.com/tosch
|
|
16
16
|
Contributors
|
17
17
|
------------
|
18
18
|
|
19
|
+
Oleg Pudeyev - http://github.com/p
|
19
20
|
Brett Anthoine - http://github.com/anb
|
20
21
|
Matt Nichols - http://github.com/mattnichols
|
21
22
|
Nicholas Faiz - http://github.com/biv
|
@@ -38,6 +39,8 @@ Richard Jennings
|
|
38
39
|
Feedback
|
39
40
|
--------
|
40
41
|
|
42
|
+
Oleg (foenixx) - many suggestions and bug reports
|
43
|
+
Avishai Shalom - discussion and ideas about participant/worker locality
|
41
44
|
Gonzalo Suarez - many help
|
42
45
|
Francisco Kiko - many help
|
43
46
|
David Goldhirsch - EM participant block
|
data/Rakefile
CHANGED
@@ -23,8 +23,8 @@ ruote is an open source ruby workflow engine.
|
|
23
23
|
gem.rubyforge_project = 'ruote'
|
24
24
|
gem.test_file = 'test/test.rb'
|
25
25
|
|
26
|
-
gem.add_dependency 'rufus-json', '>= 0.2.
|
27
|
-
gem.add_dependency 'rufus-cloche', '>= 0.1.
|
26
|
+
gem.add_dependency 'rufus-json', '>= 0.2.2'
|
27
|
+
gem.add_dependency 'rufus-cloche', '>= 0.1.17'
|
28
28
|
gem.add_dependency 'rufus-dollar'
|
29
29
|
gem.add_dependency 'rufus-lru'
|
30
30
|
gem.add_dependency 'rufus-mnemo', '>= 1.1.0'
|
@@ -48,7 +48,7 @@ end
|
|
48
48
|
begin
|
49
49
|
require 'yard'
|
50
50
|
YARD::Rake::YardocTask.new do |doc|
|
51
|
-
doc.options = [ '-o', '
|
51
|
+
doc.options = [ '-o', 'rdoc', '--title', "ruote #{Ruote::VERSION}" ]
|
52
52
|
end
|
53
53
|
rescue LoadError
|
54
54
|
task :yard do
|
@@ -65,7 +65,7 @@ desc 'Upload the documentation to rubyforge'
|
|
65
65
|
task :upload_rdoc => :yard do
|
66
66
|
sh %{
|
67
67
|
rsync -azv -e ssh \
|
68
|
-
|
68
|
+
rdoc \
|
69
69
|
jmettraux@rubyforge.org:/var/www/gforge-projects/ruote/
|
70
70
|
}
|
71
71
|
end
|
data/TODO.txt
CHANGED
@@ -193,6 +193,27 @@
|
|
193
193
|
[o] part = engine.register_participant :alpha, StorageParticipant should work...
|
194
194
|
[o] concurrence :merge_type => 'stack'
|
195
195
|
[o] CompositeStorage.new('msgs' => AmqpStorage.new(''), ...)
|
196
|
+
[x] let the storage participant leverage Ruote::FlowExpressionId.from_id(s)
|
197
|
+
[o] Andrew's technique http://groups.google.com/group/openwferu-users/browse_thread/thread/c2aa4b53d1664d45/8523a1a5ee98fd71
|
198
|
+
[o] Avishai : LocalParticipant : repost dispatch message
|
199
|
+
[o] Rdoc Ruote::Engine.register_participant -> passing a block to a participant
|
200
|
+
and perhaps also on
|
201
|
+
http://ruote.rubyforge.org/implementing_participants.html (Avish)
|
202
|
+
[o] wrap workitem in process error ? for on_error consumption (thanks Oleg)
|
203
|
+
doing workitem.fields['__error__'] = [ fei, time, error_message ]
|
204
|
+
[o] HashStorage should emit 'init persist fail' messages as well !
|
205
|
+
[o] Oleg's idea about participant on_reply
|
206
|
+
http://groups.google.com/group/openwferu-users/browse_thread/thread/2e6a95708c10847b
|
207
|
+
on_reply should be done in the receive action, not in Receiver
|
208
|
+
thus, in the ParticipantExpression
|
209
|
+
[x] exp : step (jump to cursor tag ?) : there is already the jump expression
|
210
|
+
[x] auto-participant re-apply
|
211
|
+
[o] receiver should be OK with a storage or a context
|
212
|
+
[x] Avishai : Worker : hook for rejecting the dispatch message
|
213
|
+
[o] receiver / local participant : reply/forward/proceed/... mess : fix
|
214
|
+
[o] storage participant : accept string for fei
|
215
|
+
[o] => Ruote::FlowExpressionId.extract(x)
|
216
|
+
[o] fei : place engine id in fei.to_storage_id (and back)
|
196
217
|
|
197
218
|
[ ] exp : exp (restricted form of eval ?)
|
198
219
|
[ ] exp : case (is it necessary ?)
|
@@ -200,19 +221,15 @@
|
|
200
221
|
[ ] exp : filter-definition
|
201
222
|
[x] exp : lose ?
|
202
223
|
[x] exp : parameter
|
203
|
-
[ ] exp : log
|
224
|
+
[ ] exp : log : or could it be a participant ?
|
204
225
|
|
205
226
|
[ ] exp : defined (not really necessary)
|
206
227
|
[ ] exp : quote (not really necessary)
|
207
228
|
[ ] exp : field / attribute (not really necessary)
|
208
229
|
[ ] exp : variable (not really necessary)
|
209
230
|
|
210
|
-
[ ] exp : step (jump to cursor tag ?)
|
211
|
-
|
212
231
|
[ ] conditional : rprefix ! ${r:x} is perhaps sufficient
|
213
232
|
|
214
|
-
[ ] auto-participant re-apply
|
215
|
-
|
216
233
|
[ ] define without name (__result__)
|
217
234
|
|
218
235
|
[ ] pooltool.ru
|
@@ -234,6 +251,9 @@
|
|
234
251
|
|
235
252
|
[ ] pause engine
|
236
253
|
[ ] pause process instance
|
254
|
+
|
|
255
|
+
would it mean something like placing a paused list in the storage
|
256
|
+
and fetching it all the time ?
|
237
257
|
|
238
258
|
[ ] file/fs_listener [example] ?
|
239
259
|
|
@@ -293,24 +313,25 @@
|
|
293
313
|
|
294
314
|
[ ] empty iterator or concurrent-iterator, log ? crash ? empty while...
|
295
315
|
[ ] at expression ?
|
296
|
-
[ ] listen to participants/errors/tags {in|out}
|
297
316
|
|
298
317
|
[ ] remove abort_on_exception=true
|
299
318
|
|
300
319
|
[ ] shell ? irb ? Shell.new(storage)
|
301
320
|
[ ] focus on fulldup or json.dup (via fulldup ?)
|
302
321
|
|
303
|
-
[ ]
|
304
|
-
|
322
|
+
[ ] listen to participants/errors/tags {in|out}
|
323
|
+
|
324
|
+
[x] engine.on_error = 'participant_name' // 'subprocess_name'
|
325
|
+
done at : http://github.com/jmettraux/ruote/commit/50292d954ff877f1f6615022216f346a7001b483
|
326
|
+
`--> reverting that for now, too dangerous
|
305
327
|
|
306
|
-
[ ]
|
328
|
+
[ ] should __error__ contain the tree ?
|
329
|
+
[ ] engine.on_cancel = 'participant_name' // 'subprocess_name'
|
307
330
|
|
308
331
|
[ ] "business days" plugin
|
309
332
|
|
310
333
|
[ ] issue with ruote-kit and inpa participants...
|
311
334
|
|
312
|
-
[ ] let the storage participant leverage Ruote::FlowExpressionId.from_id(s)
|
313
|
-
|
314
335
|
[ ] participant :ref => '${f:nada}', :or => 'xyz'
|
315
336
|
(look at OpenWFE manual, this feature already existed in there)
|
316
337
|
http://www.openwfe.org/manual/ch06s02.html#expression_participant
|
@@ -323,3 +344,26 @@
|
|
323
344
|
|
324
345
|
[ ] find better solution than "get all schedules"
|
325
346
|
|
347
|
+
[ ] worker : minuteman, make it cron triggerable
|
348
|
+
trap SIGUSR1 or USR2
|
349
|
+
maybe it's expensive to fire a [worker] process each minute
|
350
|
+
have to write the $$ (pid) somewhere for cron to pick it up
|
351
|
+
|
352
|
+
[ ] detach / attach segments of processes
|
353
|
+
[ ] clone process ? (could be used by {de|at}tach)
|
354
|
+
|
355
|
+
[ ] dollar.rb ${timestamp} ?
|
356
|
+
|
357
|
+
[ ] toto :task => 'maw the lawn', :within => '3d'
|
358
|
+
|
359
|
+
[ ] solve the ps#root_expression_for(fei) dilemma
|
360
|
+
|
361
|
+
[ ] engine.noisy = true shortcut
|
362
|
+
|
363
|
+
[ ] re_apply_stalled
|
364
|
+
http://groups.google.com/group/openwferu-users/browse_thread/thread/ff29f26d6b5fd135
|
365
|
+
|
366
|
+
[ ] wait_for(:inactive) blocks until worker is inactive
|
367
|
+
|
368
|
+
[ ] storage0.copy_to(storage1) / migrate_to as requested by Matt Nichols
|
369
|
+
|
data/examples/barley.rb
CHANGED
data/examples/flickr_report.rb
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
$:.unshift('lib')
|
3
3
|
|
4
4
|
require 'rubygems'
|
5
|
-
require 'ruote
|
5
|
+
require 'ruote' # sudo gem install ruote
|
6
6
|
require 'atom/feed' # sudo gem install atom-tools
|
7
7
|
require 'prawn' # sudo gem install prawn
|
8
8
|
|
9
9
|
#
|
10
10
|
# starting a transient engine (no need to make it persistent)
|
11
11
|
|
12
|
-
engine = Ruote::Engine.new(
|
12
|
+
engine = Ruote::Engine.new(Ruote::Worker.new(Ruote::HashStorage.new()))
|
13
13
|
|
14
14
|
#
|
15
15
|
# a process that fetches the latest pictures from flickr.com and submits
|
@@ -47,7 +47,7 @@ engine.register_participant :get_pictures do |workitem|
|
|
47
47
|
|
48
48
|
workitem.fields['pictures'] = feed.entries.inject([]) do |a, entry|
|
49
49
|
a << [
|
50
|
-
entry.title,
|
50
|
+
entry.title.to_s,
|
51
51
|
entry.authors.first.name,
|
52
52
|
entry.links.last.href
|
53
53
|
]
|
@@ -94,10 +94,9 @@ end
|
|
94
94
|
#
|
95
95
|
# launching the process, requesting pictures tagged 'cat' and 'fish'
|
96
96
|
|
97
|
-
|
98
|
-
li.fields['tags'] = [ 'cat', 'fish' ]
|
97
|
+
initial_workitem_fields = { 'tags' => [ 'cat', 'fish' ] }
|
99
98
|
|
100
|
-
fei = engine.launch(
|
99
|
+
fei = engine.launch(pdef, initial_workitem_fields)
|
101
100
|
|
102
101
|
#
|
103
102
|
# workflow engines are asynchronous beasts, have to wait for them
|
data/examples/web_first_page.rb
CHANGED
@@ -1,4 +1,15 @@
|
|
1
1
|
|
2
|
+
#
|
3
|
+
# This is not a runnable example, it's just a ruby source file that contains
|
4
|
+
# the samples found at
|
5
|
+
#
|
6
|
+
# http://ruote.rubyforge.org/index.html
|
7
|
+
#
|
8
|
+
# NOTE : this example need some rework. The use of block participants will
|
9
|
+
# probably be avoided
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'rubygems'
|
2
13
|
require 'ruote'
|
3
14
|
|
4
15
|
pdef = Ruote.process_definition :name => 'work' do
|
data/lib/ruote/context.rb
CHANGED
@@ -40,29 +40,53 @@ module Ruote
|
|
40
40
|
attr_accessor :worker
|
41
41
|
attr_accessor :engine
|
42
42
|
|
43
|
-
def initialize (storage,
|
43
|
+
def initialize (storage, worker=nil)
|
44
44
|
|
45
45
|
@storage = storage
|
46
|
+
@storage.context = self
|
46
47
|
|
47
|
-
@
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
end
|
48
|
+
@engine = nil
|
49
|
+
@worker = worker
|
50
|
+
|
51
|
+
@services = {}
|
52
52
|
|
53
53
|
initialize_services
|
54
54
|
end
|
55
55
|
|
56
|
+
# A trick : in order to avoid
|
57
|
+
#
|
58
|
+
# @context = o.respond_to?(:context) ? o.context : o
|
59
|
+
# # or
|
60
|
+
# #@context = o.is_a?(Ruote::Context) ? o : o.context
|
61
|
+
#
|
62
|
+
# simply letting a context say its context is itself.
|
63
|
+
#
|
64
|
+
def context
|
65
|
+
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns the engine_id (as set in the configuration under the key
|
70
|
+
# "engine_id"), or, by default, "engine".
|
71
|
+
#
|
56
72
|
def engine_id
|
57
73
|
|
58
74
|
get_conf['engine_id'] || 'engine'
|
59
75
|
end
|
60
76
|
|
77
|
+
# Used for things like
|
78
|
+
#
|
79
|
+
# if @context['ruby_eval_allowed']
|
80
|
+
# # ...
|
81
|
+
# end
|
82
|
+
#
|
61
83
|
def [] (key)
|
62
84
|
|
63
85
|
SERVICE_PREFIX.match(key) ? @services[key] : get_conf[key]
|
64
86
|
end
|
65
87
|
|
88
|
+
# Mostly used by engine#configure
|
89
|
+
#
|
66
90
|
def []= (key, value)
|
67
91
|
|
68
92
|
raise(
|
@@ -105,15 +129,14 @@ module Ruote
|
|
105
129
|
service
|
106
130
|
end
|
107
131
|
|
132
|
+
# Takes care of shutting down every service registered in this context.
|
133
|
+
#
|
108
134
|
def shutdown
|
109
135
|
|
110
136
|
@storage.shutdown if @storage.respond_to?(:shutdown)
|
111
137
|
@worker.shutdown if @worker
|
112
138
|
|
113
|
-
@services.values.each
|
114
|
-
|
115
|
-
s.shutdown if s.respond_to?(:shutdown)
|
116
|
-
end
|
139
|
+
@services.values.each { |s| s.shutdown if s.respond_to?(:shutdown) }
|
117
140
|
end
|
118
141
|
|
119
142
|
protected
|
@@ -125,8 +148,6 @@ module Ruote
|
|
125
148
|
|
126
149
|
def initialize_services
|
127
150
|
|
128
|
-
@services = {}
|
129
|
-
|
130
151
|
default_conf.merge(get_conf).each do |key, value|
|
131
152
|
|
132
153
|
next unless SERVICE_PREFIX.match(key)
|
@@ -152,7 +173,9 @@ module Ruote
|
|
152
173
|
's_dispatch_pool' => [
|
153
174
|
'ruote/part/dispatch_pool', 'Ruote::DispatchPool' ],
|
154
175
|
's_logger' => [
|
155
|
-
'ruote/log/wait_logger', 'Ruote::WaitLogger' ]
|
176
|
+
'ruote/log/wait_logger', 'Ruote::WaitLogger' ],
|
177
|
+
's_error_handler' => [
|
178
|
+
'ruote/error_handler', 'Ruote::ErrorHandler' ] }
|
156
179
|
end
|
157
180
|
end
|
158
181
|
end
|
data/lib/ruote/engine.rb
CHANGED
@@ -29,69 +29,63 @@ require 'ruote/receiver/base'
|
|
29
29
|
|
30
30
|
module Ruote
|
31
31
|
|
32
|
+
#
|
33
|
+
# This class holds the 'engine' name, perhaps 'dashboard' would have been
|
34
|
+
# a better name. Anyway, the methods here allow to launch processes
|
35
|
+
# and to query about their status. There are also methods for fixing
|
36
|
+
# issues with stalled processes or processes stuck in errors.
|
37
|
+
#
|
38
|
+
# NOTE : the methods #launch and #reply are implemented in
|
39
|
+
# Ruote::ReceiverMixin
|
40
|
+
#
|
32
41
|
class Engine
|
33
42
|
|
34
43
|
include ReceiverMixin
|
35
44
|
|
36
|
-
attr_reader :storage
|
37
|
-
attr_reader :worker
|
38
45
|
attr_reader :context
|
39
46
|
attr_reader :variables
|
40
47
|
|
41
48
|
def initialize (worker_or_storage, run=true)
|
42
49
|
|
43
|
-
|
50
|
+
@context = worker_or_storage.context
|
51
|
+
@context.engine = self
|
44
52
|
|
45
|
-
|
46
|
-
@storage = @worker.storage
|
47
|
-
@context = @worker.context
|
48
|
-
@context.engine = self
|
49
|
-
else
|
53
|
+
@variables = EngineVariables.new(@context.storage)
|
50
54
|
|
51
|
-
|
52
|
-
|
53
|
-
@context = Ruote::Context.new(@storage, self)
|
54
|
-
end
|
55
|
-
|
56
|
-
@variables = EngineVariables.new(@storage)
|
57
|
-
|
58
|
-
@worker.run_in_thread if @worker && run
|
55
|
+
@context.worker.run_in_thread if @context.worker && run
|
56
|
+
# launch the worker if there is one
|
59
57
|
end
|
60
58
|
|
61
|
-
def
|
59
|
+
def storage
|
62
60
|
|
63
|
-
|
61
|
+
@context.storage
|
62
|
+
end
|
64
63
|
|
65
|
-
|
66
|
-
'launch',
|
67
|
-
'wfid' => wfid,
|
68
|
-
'tree' => @context.parser.parse(process_definition),
|
69
|
-
'workitem' => { 'fields' => fields },
|
70
|
-
'variables' => variables)
|
64
|
+
def worker
|
71
65
|
|
72
|
-
|
66
|
+
@context.worker
|
73
67
|
end
|
74
68
|
|
75
69
|
def cancel_process (wfid)
|
76
70
|
|
77
|
-
@storage.put_msg('cancel_process', 'wfid' => wfid)
|
71
|
+
@context.storage.put_msg('cancel_process', 'wfid' => wfid)
|
78
72
|
end
|
79
73
|
|
80
74
|
def kill_process (wfid)
|
81
75
|
|
82
|
-
@storage.put_msg('kill_process', 'wfid' => wfid)
|
76
|
+
@context.storage.put_msg('kill_process', 'wfid' => wfid)
|
83
77
|
end
|
84
78
|
|
85
79
|
def cancel_expression (fei)
|
86
80
|
|
87
81
|
fei = fei.to_h if fei.respond_to?(:to_h)
|
88
|
-
@storage.put_msg('cancel', 'fei' => fei)
|
82
|
+
@context.storage.put_msg('cancel', 'fei' => fei)
|
89
83
|
end
|
90
84
|
|
91
85
|
def kill_expression (fei)
|
92
86
|
|
93
87
|
fei = fei.to_h if fei.respond_to?(:to_h)
|
94
|
-
@storage.put_msg('cancel', 'fei' => fei, 'flavour' => 'kill')
|
88
|
+
@context.storage.put_msg('cancel', 'fei' => fei, 'flavour' => 'kill')
|
95
89
|
end
|
96
90
|
|
97
91
|
# Replays at a given error (hopefully you fixed the cause of the error
|
@@ -113,9 +107,9 @@ module Ruote
|
|
113
107
|
exp.unpersist_or_raise if exp
|
114
108
|
end
|
115
109
|
|
116
|
-
@storage.delete(err.to_h) # remove error
|
110
|
+
@context.storage.delete(err.to_h) # remove error
|
117
111
|
|
118
|
-
@storage.put_msg(action, msg) # trigger replay
|
112
|
+
@context.storage.put_msg(action, msg) # trigger replay
|
119
113
|
end
|
120
114
|
|
121
115
|
# Re-applies an expression (given via its FlowExpressionId).
|
@@ -148,7 +142,7 @@ module Ruote
|
|
148
142
|
#
|
149
143
|
def process (wfid)
|
150
144
|
|
151
|
-
exps = @storage.get_many('expressions', /!#{wfid}$/)
|
145
|
+
exps = @context.storage.get_many('expressions', /!#{wfid}$/)
|
152
146
|
errs = self.errors( wfid )
|
153
147
|
|
154
148
|
return nil if exps.empty? && errs.empty?
|
@@ -162,7 +156,7 @@ module Ruote
|
|
162
156
|
#
|
163
157
|
def processes
|
164
158
|
|
165
|
-
exps = @storage.get_many('expressions')
|
159
|
+
exps = @context.storage.get_many('expressions')
|
166
160
|
errs = self.errors
|
167
161
|
|
168
162
|
by_wfid = {}
|
@@ -181,10 +175,13 @@ module Ruote
|
|
181
175
|
#
|
182
176
|
def errors( wfid = nil )
|
183
177
|
wfid.nil? ?
|
184
|
-
@storage.get_many('errors') :
|
185
|
-
@storage.get_many('errors', /!#{wfid}$/)
|
178
|
+
@context.storage.get_many('errors') :
|
179
|
+
@context.storage.get_many('errors', /!#{wfid}$/)
|
186
180
|
end
|
187
181
|
|
182
|
+
# Shuts down the engine, mostly passes the shutdown message to the other
|
183
|
+
# services and hope they'll shut down properly.
|
184
|
+
#
|
188
185
|
def shutdown
|
189
186
|
|
190
187
|
@context.shutdown
|
@@ -207,7 +204,16 @@ module Ruote
|
|
207
204
|
# # will make the current thread block until 5 messages have been
|
208
205
|
# # processed on the workqueue...
|
209
206
|
#
|
210
|
-
|
207
|
+
# engine.wait_for(:empty)
|
208
|
+
# # will return as soon as the engine/storage is empty, ie as soon
|
209
|
+
# # as there are no more processes running in the engine (no more
|
210
|
+
# # expressions placed in the storage)
|
211
|
+
#
|
212
|
+
# It's OK to wait for multiple wfids :
|
213
|
+
#
|
214
|
+
# engine.wait_for('20100612-bezerijozo', '20100612-yakisoba')
|
215
|
+
#
|
216
|
+
def wait_for (*items)
|
211
217
|
|
212
218
|
logger = @context['s_logger']
|
213
219
|
|
@@ -215,7 +221,7 @@ module Ruote
|
|
215
221
|
"can't wait_for, there is no logger that responds to that call"
|
216
222
|
) unless logger.respond_to?(:wait_for)
|
217
223
|
|
218
|
-
logger.wait_for(
|
224
|
+
logger.wait_for(items)
|
219
225
|
end
|
220
226
|
|
221
227
|
# Loads and parses the process definition at the given path.
|
@@ -255,37 +261,42 @@ module Ruote
|
|
255
261
|
# engine.register_participant /^moon-.+/, MyParticipant.new('Saturn-V')
|
256
262
|
#
|
257
263
|
#
|
258
|
-
# ==
|
264
|
+
# == 'stateless' participants are preferred over 'stateful' ones
|
259
265
|
#
|
260
|
-
#
|
266
|
+
# Ruote 2.1 is OK with 1 storage and 1+ workers. The workers may be
|
267
|
+
# in other ruby runtimes. This implies that if you have registered a
|
268
|
+
# participant instance (instead of passing its classname and options),
|
269
|
+
# that participant will only run in the worker 'embedded' in the engine
|
270
|
+
# where it was registered... Let me rephrase it, participants instantiated
|
271
|
+
# at registration time (and that includes block participants) only runs
|
272
|
+
# in one worker, always the same.
|
261
273
|
#
|
262
|
-
#
|
263
|
-
#
|
264
|
-
# end
|
274
|
+
# 'stateless' participants, instantiated at each dispatch, are preferred.
|
275
|
+
# Any worker can handle them.
|
265
276
|
#
|
266
|
-
#
|
277
|
+
# Block participants are still fine for demos (where the worker is included
|
278
|
+
# in the engine (see all the quickstarts). And small engines with 1 worker
|
279
|
+
# are not that bad, not everybody is building huge systems).
|
267
280
|
#
|
268
|
-
#
|
281
|
+
# Here is a 'stateless' participant example :
|
269
282
|
#
|
270
|
-
# class
|
271
|
-
# include Ruote::LocalParticipant
|
283
|
+
# class MyStatelessParticipant
|
272
284
|
# def initialize (opts)
|
273
|
-
# @
|
274
|
-
# @block = opts[:block]
|
285
|
+
# @opts = opts
|
275
286
|
# end
|
276
287
|
# def consume (workitem)
|
277
|
-
# workitem.fields['
|
278
|
-
# workitem
|
279
|
-
#
|
280
|
-
#
|
288
|
+
# workitem.fields['rocket_name'] = @opts['name']
|
289
|
+
# send_to_the_moon(workitem)
|
290
|
+
# end
|
291
|
+
# def cancel (fei, flavour)
|
292
|
+
# # do nothing
|
281
293
|
# end
|
282
294
|
# end
|
283
295
|
#
|
284
|
-
# engine.register_participant '
|
285
|
-
# wi.fields['nada'] = surf
|
286
|
-
# end
|
296
|
+
# engine.register_participant 'moon', MyStatelessParticipant, 'name' => 'saturn5'
|
287
297
|
#
|
288
|
-
#
|
298
|
+
# Remember that the options (the hash that follows the class name), must be
|
299
|
+
# serialisable via JSON.
|
289
300
|
#
|
290
301
|
def register_participant (regex, participant=nil, opts={}, &block)
|
291
302
|
|
@@ -341,6 +352,27 @@ module Ruote
|
|
341
352
|
|
342
353
|
@context[config_key] = value
|
343
354
|
end
|
355
|
+
|
356
|
+
# A convenience methods for advanced users (like Oleg).
|
357
|
+
#
|
358
|
+
# Given a fei (flow expression id), fetches the workitem as stored in
|
359
|
+
# the expression with that fei.
|
360
|
+
# This is the "applied workitem", if the workitem is currently handed to
|
361
|
+
# a participant, this method will return the workitem as applied, not
|
362
|
+
# the workitem as saved by the participant/user in whatever worklist it
|
363
|
+
# uses. If you need that workitem, do the vanilla thing and ask it to
|
364
|
+
# the [storage] participant or its worklist.
|
365
|
+
#
|
366
|
+
# The fei might be a string fei (result of fei.to_storage_id), a
|
367
|
+
# FlowExpressionId instance or a hash.
|
368
|
+
#
|
369
|
+
def workitem (fei)
|
370
|
+
|
371
|
+
fexp = Ruote::Exp::FlowExpression.fetch(
|
372
|
+
@context, Ruote::FlowExpressionId.extract_h(fei))
|
373
|
+
|
374
|
+
Ruote::Workitem.new(fexp.h.applied_workitem)
|
375
|
+
end
|
344
376
|
end
|
345
377
|
|
346
378
|
#
|