ruote 2.2.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +166 -1
- data/CREDITS.txt +36 -17
- data/LICENSE.txt +1 -1
- data/README.rdoc +1 -7
- data/Rakefile +38 -29
- data/TODO.txt +93 -52
- data/lib/ruote-fs.rb +3 -0
- data/lib/ruote.rb +5 -1
- data/lib/ruote/context.rb +140 -35
- data/lib/ruote/dashboard.rb +1247 -0
- data/lib/ruote/{engine → dboard}/process_error.rb +22 -2
- data/lib/ruote/dboard/process_status.rb +587 -0
- data/lib/ruote/engine.rb +6 -871
- data/lib/ruote/exp/command.rb +7 -2
- data/lib/ruote/exp/commanded.rb +2 -2
- data/lib/ruote/exp/condition.rb +38 -13
- data/lib/ruote/exp/fe_add_branches.rb +1 -1
- data/lib/ruote/exp/fe_apply.rb +1 -1
- data/lib/ruote/exp/fe_await.rb +357 -0
- data/lib/ruote/exp/fe_cancel_process.rb +17 -3
- data/lib/ruote/exp/fe_command.rb +8 -4
- data/lib/ruote/exp/fe_concurrence.rb +218 -18
- data/lib/ruote/exp/fe_concurrent_iterator.rb +71 -10
- data/lib/ruote/exp/fe_cron.rb +3 -10
- data/lib/ruote/exp/fe_cursor.rb +14 -4
- data/lib/ruote/exp/fe_define.rb +3 -1
- data/lib/ruote/exp/fe_echo.rb +1 -1
- data/lib/ruote/exp/fe_equals.rb +1 -1
- data/lib/ruote/exp/fe_error.rb +1 -1
- data/lib/ruote/exp/fe_filter.rb +163 -4
- data/lib/ruote/exp/fe_forget.rb +21 -4
- data/lib/ruote/exp/fe_given.rb +1 -1
- data/lib/ruote/exp/fe_if.rb +1 -1
- data/lib/ruote/exp/fe_inc.rb +102 -35
- data/lib/ruote/exp/fe_iterator.rb +47 -12
- data/lib/ruote/exp/fe_listen.rb +96 -11
- data/lib/ruote/exp/fe_lose.rb +31 -4
- data/lib/ruote/exp/fe_noop.rb +1 -1
- data/lib/ruote/exp/fe_on_error.rb +109 -0
- data/lib/ruote/exp/fe_once.rb +10 -19
- data/lib/ruote/exp/fe_participant.rb +90 -28
- data/lib/ruote/exp/fe_read.rb +69 -0
- data/lib/ruote/exp/fe_redo.rb +3 -2
- data/lib/ruote/exp/fe_ref.rb +57 -27
- data/lib/ruote/exp/fe_registerp.rb +1 -3
- data/lib/ruote/exp/fe_reserve.rb +1 -1
- data/lib/ruote/exp/fe_restore.rb +6 -6
- data/lib/ruote/exp/fe_save.rb +12 -19
- data/lib/ruote/exp/fe_sequence.rb +38 -2
- data/lib/ruote/exp/fe_set.rb +143 -40
- data/lib/ruote/exp/{fe_let.rb → fe_stall.rb} +7 -38
- data/lib/ruote/exp/fe_subprocess.rb +8 -2
- data/lib/ruote/exp/fe_that.rb +1 -1
- data/lib/ruote/exp/fe_undo.rb +40 -4
- data/lib/ruote/exp/fe_unregisterp.rb +1 -3
- data/lib/ruote/exp/fe_wait.rb +12 -25
- data/lib/ruote/exp/{flowexpression.rb → flow_expression.rb} +375 -229
- data/lib/ruote/exp/iterator.rb +2 -2
- data/lib/ruote/exp/merge.rb +78 -17
- data/lib/ruote/exp/ro_attributes.rb +46 -36
- data/lib/ruote/exp/ro_filters.rb +34 -8
- data/lib/ruote/exp/ro_on_x.rb +431 -0
- data/lib/ruote/exp/ro_persist.rb +19 -7
- data/lib/ruote/exp/ro_timers.rb +123 -0
- data/lib/ruote/exp/ro_variables.rb +90 -29
- data/lib/ruote/fei.rb +57 -3
- data/lib/ruote/fs.rb +3 -0
- data/lib/ruote/id/mnemo_wfid_generator.rb +30 -7
- data/lib/ruote/id/wfid_generator.rb +17 -38
- data/lib/ruote/log/default_history.rb +23 -9
- data/lib/ruote/log/fancy_printing.rb +265 -0
- data/lib/ruote/log/storage_history.rb +23 -13
- data/lib/ruote/log/wait_logger.rb +224 -17
- data/lib/ruote/observer.rb +82 -0
- data/lib/ruote/part/block_participant.rb +65 -28
- data/lib/ruote/part/code_participant.rb +81 -0
- data/lib/ruote/part/engine_participant.rb +7 -2
- data/lib/ruote/part/local_participant.rb +221 -21
- data/lib/ruote/part/no_op_participant.rb +1 -1
- data/lib/ruote/part/null_participant.rb +1 -1
- data/lib/ruote/part/participant.rb +50 -0
- data/lib/ruote/part/rev_participant.rb +178 -0
- data/lib/ruote/part/smtp_participant.rb +2 -2
- data/lib/ruote/part/storage_participant.rb +228 -60
- data/lib/ruote/part/template.rb +1 -1
- data/lib/ruote/participant.rb +2 -0
- data/lib/ruote/reader.rb +205 -68
- data/lib/ruote/reader/json.rb +49 -0
- data/lib/ruote/reader/radial.rb +303 -0
- data/lib/ruote/reader/ruby_dsl.rb +44 -9
- data/lib/ruote/reader/xml.rb +11 -8
- data/lib/ruote/receiver/base.rb +98 -45
- data/lib/ruote/storage/base.rb +104 -35
- data/lib/ruote/storage/composite_storage.rb +50 -60
- data/lib/ruote/storage/fs_storage.rb +25 -34
- data/lib/ruote/storage/hash_storage.rb +38 -36
- data/lib/ruote/svc/dispatch_pool.rb +104 -35
- data/lib/ruote/svc/dollar_sub.rb +10 -8
- data/lib/ruote/svc/error_handler.rb +108 -52
- data/lib/ruote/svc/expression_map.rb +3 -3
- data/lib/ruote/svc/participant_list.rb +160 -55
- data/lib/ruote/svc/tracker.rb +31 -31
- data/lib/ruote/svc/treechecker.rb +28 -16
- data/lib/ruote/tree_dot.rb +1 -1
- data/lib/ruote/util/deep.rb +143 -0
- data/lib/ruote/util/filter.rb +125 -18
- data/lib/ruote/util/hashdot.rb +15 -13
- data/lib/ruote/util/look.rb +1 -1
- data/lib/ruote/util/lookup.rb +60 -22
- data/lib/ruote/util/misc.rb +63 -18
- data/lib/ruote/util/mpatch.rb +53 -0
- data/lib/ruote/util/ometa.rb +1 -2
- data/lib/ruote/util/process_observer.rb +177 -0
- data/lib/ruote/util/subprocess.rb +1 -1
- data/lib/ruote/util/time.rb +2 -2
- data/lib/ruote/util/tree.rb +64 -2
- data/lib/ruote/version.rb +3 -2
- data/lib/ruote/worker.rb +421 -92
- data/lib/ruote/workitem.rb +157 -22
- data/ruote.gemspec +15 -9
- data/test/bm/ci.rb +0 -2
- data/test/bm/ici.rb +0 -2
- data/test/bm/load_26c.rb +0 -3
- data/test/bm/mega.rb +0 -2
- data/test/functional/base.rb +57 -43
- data/test/functional/concurrent_base.rb +16 -13
- data/test/functional/ct_0_concurrence.rb +7 -11
- data/test/functional/ct_1_iterator.rb +9 -11
- data/test/functional/ct_2_cancel.rb +28 -17
- data/test/functional/eft_0_flow_expression.rb +35 -0
- data/test/functional/eft_10_cancel_process.rb +1 -1
- data/test/functional/eft_11_wait.rb +13 -13
- data/test/functional/eft_12_listen.rb +199 -66
- data/test/functional/eft_13_iterator.rb +95 -29
- data/test/functional/eft_14_cursor.rb +74 -24
- data/test/functional/eft_15_loop.rb +7 -7
- data/test/functional/eft_16_if.rb +1 -1
- data/test/functional/eft_17_equals.rb +1 -1
- data/test/functional/eft_18_concurrent_iterator.rb +156 -68
- data/test/functional/eft_19_reserve.rb +15 -15
- data/test/functional/eft_1_echo.rb +1 -1
- data/test/functional/eft_20_save.rb +51 -9
- data/test/functional/eft_21_restore.rb +1 -1
- data/test/functional/eft_22_noop.rb +1 -1
- data/test/functional/eft_23_apply.rb +1 -1
- data/test/functional/eft_24_add_branches.rb +7 -8
- data/test/functional/eft_25_command.rb +1 -1
- data/test/functional/eft_26_error.rb +11 -11
- data/test/functional/eft_27_inc.rb +111 -67
- data/test/functional/eft_28_once.rb +16 -16
- data/test/functional/eft_29_cron.rb +9 -9
- data/test/functional/eft_2_sequence.rb +23 -4
- data/test/functional/eft_30_ref.rb +36 -24
- data/test/functional/eft_31_registerp.rb +24 -24
- data/test/functional/eft_32_lose.rb +46 -20
- data/test/functional/eft_34_given.rb +1 -1
- data/test/functional/eft_35_filter.rb +161 -7
- data/test/functional/eft_36_read.rb +97 -0
- data/test/functional/{eft_0_process_definition.rb → eft_37_process_definition.rb} +4 -4
- data/test/functional/eft_38_on_error.rb +195 -0
- data/test/functional/eft_39_stall.rb +35 -0
- data/test/functional/eft_3_participant.rb +77 -22
- data/test/functional/eft_40_await.rb +297 -0
- data/test/functional/eft_4_set.rb +110 -11
- data/test/functional/eft_5_subprocess.rb +27 -5
- data/test/functional/eft_6_concurrence.rb +299 -60
- data/test/functional/eft_7_forget.rb +24 -22
- data/test/functional/eft_8_undo.rb +52 -15
- data/test/functional/eft_9_redo.rb +18 -20
- data/test/functional/ft_0_worker.rb +122 -13
- data/test/functional/ft_10_dollar.rb +77 -16
- data/test/functional/ft_11_recursion.rb +9 -9
- data/test/functional/ft_12_launchitem.rb +7 -9
- data/test/functional/ft_13_variables.rb +125 -22
- data/test/functional/ft_14_re_apply.rb +112 -56
- data/test/functional/ft_15_timeout.rb +64 -33
- data/test/functional/ft_16_participant_params.rb +59 -6
- data/test/functional/ft_17_conditional.rb +68 -2
- data/test/functional/ft_18_kill.rb +48 -30
- data/test/functional/ft_19_participant_code.rb +67 -0
- data/test/functional/ft_1_process_status.rb +222 -150
- data/test/functional/ft_20_storage_participant.rb +445 -44
- data/test/functional/ft_21_forget.rb +21 -26
- data/test/functional/ft_22_process_definitions.rb +8 -6
- data/test/functional/ft_23_load_defs.rb +29 -5
- data/test/functional/ft_24_block_participant.rb +199 -20
- data/test/functional/ft_25_receiver.rb +98 -46
- data/test/functional/ft_26_participant_rtimeout.rb +34 -26
- data/test/functional/ft_27_var_indirection.rb +40 -5
- data/test/functional/ft_28_null_noop_participants.rb +5 -5
- data/test/functional/ft_29_part_template.rb +2 -2
- data/test/functional/ft_2_errors.rb +106 -74
- data/test/functional/ft_30_smtp_participant.rb +7 -7
- data/test/functional/ft_31_part_blocking.rb +11 -11
- data/test/functional/ft_32_scope.rb +50 -0
- data/test/functional/ft_33_participant_subprocess_priority.rb +3 -3
- data/test/functional/ft_34_cursor_rewind.rb +14 -14
- data/test/functional/ft_35_add_service.rb +67 -9
- data/test/functional/ft_36_storage_history.rb +92 -24
- data/test/functional/ft_37_default_history.rb +35 -23
- data/test/functional/ft_38_participant_more.rb +189 -32
- data/test/functional/ft_39_wait_for.rb +25 -25
- data/test/functional/ft_3_participant_registration.rb +235 -107
- data/test/functional/ft_40_wait_logger.rb +105 -18
- data/test/functional/ft_41_participants.rb +13 -12
- data/test/functional/ft_42_storage_copy.rb +12 -12
- data/test/functional/ft_43_participant_on_reply.rb +85 -11
- data/test/functional/ft_44_var_participant.rb +5 -5
- data/test/functional/ft_45_participant_accept.rb +3 -3
- data/test/functional/ft_46_launch_single.rb +17 -17
- data/test/functional/ft_47_wfids.rb +41 -0
- data/test/functional/ft_48_lose.rb +19 -25
- data/test/functional/ft_49_engine_on_error.rb +54 -70
- data/test/functional/ft_4_cancel.rb +84 -26
- data/test/functional/ft_50_engine_config.rb +4 -4
- data/test/functional/ft_51_misc.rb +12 -12
- data/test/functional/ft_52_case.rb +17 -17
- data/test/functional/ft_53_engine_on_terminate.rb +18 -21
- data/test/functional/ft_54_patterns.rb +18 -16
- data/test/functional/ft_55_engine_participant.rb +55 -55
- data/test/functional/ft_56_filter_attribute.rb +90 -52
- data/test/functional/ft_57_rev_participant.rb +252 -0
- data/test/functional/ft_58_workitem.rb +150 -0
- data/test/functional/ft_59_pause.rb +329 -0
- data/test/functional/ft_5_on_error.rb +430 -77
- data/test/functional/ft_60_code_participant.rb +65 -0
- data/test/functional/ft_61_trailing_fields.rb +34 -0
- data/test/functional/ft_62_exp_name_and_dollar_substitution.rb +35 -0
- data/test/functional/ft_63_participants_221.rb +458 -0
- data/test/functional/ft_64_stash.rb +41 -0
- data/test/functional/ft_65_timers.rb +313 -0
- data/test/functional/ft_66_flank.rb +133 -0
- data/test/functional/ft_67_radial_misc.rb +34 -0
- data/test/functional/ft_68_reput.rb +72 -0
- data/test/functional/ft_69_worker_info.rb +56 -0
- data/test/functional/ft_6_on_cancel.rb +189 -36
- data/test/functional/ft_70_take_and_discard_attributes.rb +94 -0
- data/test/functional/ft_71_retries.rb +144 -0
- data/test/functional/ft_72_on_terminate.rb +60 -0
- data/test/functional/ft_73_raise_msg.rb +107 -0
- data/test/functional/ft_74_respark.rb +106 -0
- data/test/functional/ft_75_context.rb +66 -0
- data/test/functional/ft_76_observer.rb +53 -0
- data/test/functional/ft_77_process_observer.rb +157 -0
- data/test/functional/ft_78_part_participant.rb +37 -0
- data/test/functional/ft_7_tags.rb +238 -50
- data/test/functional/ft_8_participant_consumption.rb +27 -21
- data/test/functional/ft_9_subprocesses.rb +48 -18
- data/test/functional/restart_base.rb +4 -6
- data/test/functional/rt_0_wait.rb +10 -10
- data/test/functional/rt_1_listen.rb +6 -6
- data/test/functional/rt_2_errors.rb +12 -12
- data/test/functional/rt_3_once.rb +17 -12
- data/test/functional/rt_4_cron.rb +17 -17
- data/test/functional/rt_5_timeout.rb +13 -13
- data/test/functional/signals.rb +103 -0
- data/test/functional/storage.rb +730 -0
- data/test/functional/storage_helper.rb +48 -35
- data/test/functional/test.rb +6 -2
- data/test/misc/idle.rb +21 -0
- data/test/misc/light.rb +29 -0
- data/test/path_helper.rb +1 -1
- data/test/test.rb +2 -5
- data/test/test_helper.rb +13 -0
- data/test/unit/test.rb +1 -4
- data/test/unit/ut_0_ruby_reader.rb +25 -9
- data/test/unit/ut_10_participants.rb +47 -0
- data/test/unit/ut_11_lookup.rb +59 -2
- data/test/unit/ut_12_wait_logger.rb +123 -0
- data/test/unit/ut_14_is_uri.rb +1 -1
- data/test/unit/ut_15_util.rb +1 -1
- data/test/unit/ut_16_reader.rb +136 -14
- data/test/unit/ut_17_merge.rb +155 -0
- data/test/unit/ut_19_part_template.rb +1 -1
- data/test/unit/ut_1_fei.rb +11 -2
- data/test/unit/ut_20_composite_storage.rb +27 -1
- data/test/unit/{ut_21_participant_list.rb → ut_21_svc_participant_list.rb} +2 -3
- data/test/unit/ut_22_filter.rb +231 -10
- data/test/unit/ut_23_svc_tracker.rb +48 -0
- data/test/unit/ut_24_radial_reader.rb +458 -0
- data/test/unit/ut_25_process_status.rb +143 -0
- data/test/unit/ut_26_deep.rb +131 -0
- data/test/unit/ut_2_dashboard.rb +114 -0
- data/test/unit/ut_3_worker.rb +54 -0
- data/test/unit/ut_4_expmap.rb +1 -1
- data/test/unit/ut_5_tree.rb +23 -23
- data/test/unit/ut_6_condition.rb +71 -29
- data/test/unit/ut_7_workitem.rb +18 -4
- data/test/unit/ut_8_tree_to_dot.rb +1 -1
- data/test/unit/ut_9_xml_reader.rb +1 -1
- metadata +142 -63
- data/jruby_issue.txt +0 -32
- data/lib/ruote/engine/process_status.rb +0 -403
- data/lib/ruote/log/pretty.rb +0 -165
- data/lib/ruote/log/test_logger.rb +0 -204
- data/lib/ruote/util/serializer.rb +0 -103
- data/phil.txt +0 -14
- data/test/functional/eft_33_let.rb +0 -31
- data/test/functional/ft_19_alias.rb +0 -33
- data/test/functional/ft_47_wfid_generator.rb +0 -54
- data/test/unit/storage.rb +0 -403
- data/test/unit/storages.rb +0 -37
- data/test/unit/ut_13_serializer.rb +0 -65
- data/test/unit/ut_18_engine.rb +0 -47
- data/test/unit/ut_3_wait_logger.rb +0 -39
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2005-
|
2
|
+
# Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
5
|
# of this software and associated documentation files (the "Software"), to deal
|
@@ -183,7 +183,13 @@ module Ruote::Exp
|
|
183
183
|
|
184
184
|
pos, subtree = Ruote.lookup_subprocess(self, ref)
|
185
185
|
|
186
|
-
|
186
|
+
fs, vs = compile_atts.partition { |k, v| k.match(/^f(ield)?:./) }
|
187
|
+
|
188
|
+
fields = h.applied_workitem['fields']
|
189
|
+
fs.each { |k, v| Ruote.set(fields, k.split(':', 2).last, v) }
|
190
|
+
|
191
|
+
vars = Hash[vs.collect { |k, v| [ k.split(':', 2).last, v ] }]
|
192
|
+
|
187
193
|
vars.merge!('tree' => tree_children.first)
|
188
194
|
# NOTE : we're taking the first child here...
|
189
195
|
|
data/lib/ruote/exp/fe_that.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2005-
|
2
|
+
# Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
5
|
# of this software and associated documentation files (the "Software"), to deal
|
data/lib/ruote/exp/fe_undo.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2005-
|
2
|
+
# Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
5
|
# of this software and associated documentation files (the "Software"), to deal
|
@@ -44,16 +44,52 @@ module Ruote::Exp
|
|
44
44
|
#
|
45
45
|
# cancel :ref => 'invoicing_stage'
|
46
46
|
#
|
47
|
+
# == a bit shorter
|
48
|
+
#
|
49
|
+
# It's OK to shorten
|
50
|
+
#
|
51
|
+
# cancel :ref => 'invoicing_stage'
|
52
|
+
#
|
53
|
+
# to
|
54
|
+
#
|
55
|
+
# cancel 'invoicing_stage'
|
56
|
+
#
|
57
|
+
# == kill
|
58
|
+
#
|
59
|
+
# kill :ref => 'invoicing stage'
|
60
|
+
#
|
61
|
+
# will cancel the target expression and bypass any on_cancel handler set for
|
62
|
+
# it.
|
63
|
+
#
|
64
|
+
# concurrence do
|
65
|
+
# sequence :tag => 'x', :on_cancel => 'y' do
|
66
|
+
# # ...
|
67
|
+
# end
|
68
|
+
# sequence do
|
69
|
+
# # ...
|
70
|
+
# kill 'x'
|
71
|
+
# end
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# In this example the :on_cancel => 'y' will get ignored if kill 'x' kicks
|
75
|
+
# in.
|
76
|
+
#
|
47
77
|
class UndoExpression < FlowExpression
|
48
78
|
|
49
|
-
names :undo, :cancel
|
79
|
+
names :undo, :cancel, :kill
|
50
80
|
|
51
81
|
def apply
|
52
82
|
|
53
83
|
ref = attribute(:ref) || attribute_text
|
54
|
-
|
84
|
+
ref = ref.strip if ref
|
85
|
+
|
86
|
+
tag = (ref && ref != '') ? lookup_variable(ref) : nil
|
55
87
|
|
56
|
-
@context.storage.put_msg(
|
88
|
+
@context.storage.put_msg(
|
89
|
+
'cancel',
|
90
|
+
'fei' => tag,
|
91
|
+
'flavour' => self.name == 'kill' ? 'kill' : nil
|
92
|
+
) if Ruote.is_a_fei?(tag)
|
57
93
|
|
58
94
|
reply_to_parent(h.applied_workitem)
|
59
95
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2005-
|
2
|
+
# Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
5
|
# of this software and associated documentation files (the "Software"), to deal
|
@@ -27,8 +27,6 @@ require 'ruote/exp/fe_registerp'
|
|
27
27
|
|
28
28
|
module Ruote::Exp
|
29
29
|
|
30
|
-
#
|
31
|
-
# (Since ruote 2.1.12)
|
32
30
|
#
|
33
31
|
# Unregisters a participant.
|
34
32
|
#
|
data/lib/ruote/exp/fe_wait.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2005-
|
2
|
+
# Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
5
|
# of this software and associated documentation files (the "Software"), to deal
|
@@ -56,27 +56,20 @@ module Ruote::Exp
|
|
56
56
|
h.for = attribute(:for) || attribute_text
|
57
57
|
h.until = attribute(:until)
|
58
58
|
|
59
|
-
|
60
|
-
|
59
|
+
h.at = h.for
|
60
|
+
h.at = h.until if h.at == ''
|
61
61
|
|
62
|
-
h.
|
62
|
+
return reply_to_parent(h.applied_workitem) unless h.at
|
63
63
|
|
64
|
-
|
64
|
+
h.schedule_id = @context.storage.put_schedule(
|
65
|
+
'at',
|
66
|
+
h.fei,
|
67
|
+
h.at,
|
68
|
+
'action' => 'reply',
|
69
|
+
'fei' => h.fei,
|
70
|
+
'workitem' => h.applied_workitem)
|
65
71
|
|
66
|
-
|
67
|
-
'at',
|
68
|
-
h.fei,
|
69
|
-
h.at,
|
70
|
-
'action' => 'reply',
|
71
|
-
'fei' => h.fei,
|
72
|
-
'workitem' => h.applied_workitem)
|
73
|
-
|
74
|
-
persist_or_raise
|
75
|
-
|
76
|
-
else
|
77
|
-
|
78
|
-
reply_to_parent(h.applied_workitem)
|
79
|
-
end
|
72
|
+
persist_or_raise
|
80
73
|
end
|
81
74
|
|
82
75
|
#--
|
@@ -84,12 +77,6 @@ module Ruote::Exp
|
|
84
77
|
#def reply (workitem)
|
85
78
|
#end
|
86
79
|
#++
|
87
|
-
|
88
|
-
def cancel(flavour)
|
89
|
-
|
90
|
-
@context.storage.delete_schedule(h.schedule_id)
|
91
|
-
reply_to_parent(h.applied_workitem)
|
92
|
-
end
|
93
80
|
end
|
94
81
|
end
|
95
82
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2005-
|
2
|
+
# Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
5
|
# of this software and associated documentation files (the "Software"), to deal
|
@@ -52,20 +52,50 @@ module Ruote::Exp
|
|
52
52
|
#
|
53
53
|
# Each node is an expression...
|
54
54
|
#
|
55
|
+
#
|
56
|
+
# == the states of an expression
|
57
|
+
#
|
58
|
+
# === nil
|
59
|
+
# the normal state
|
60
|
+
#
|
61
|
+
# === 'cancelling'
|
62
|
+
# the expression and its children are getting cancelled
|
63
|
+
#
|
64
|
+
# === 'dying'
|
65
|
+
# the expression and its children are getting killed
|
66
|
+
#
|
67
|
+
# === 'failed'
|
68
|
+
# the expression has finishing
|
69
|
+
#
|
70
|
+
# === 'failing'
|
71
|
+
# the expression just failed and it's cancelling its children
|
72
|
+
#
|
73
|
+
# === 'timing_out'
|
74
|
+
# the expression just timedout and it's cancelling its children
|
75
|
+
#
|
76
|
+
# === 'paused'
|
77
|
+
# the expression is paused, it will store downstream messages and play
|
78
|
+
# them only when a 'resume' message comes from upstream.
|
79
|
+
#
|
55
80
|
class FlowExpression
|
56
81
|
|
57
82
|
include Ruote::WithH
|
58
83
|
include Ruote::WithMeta
|
59
84
|
|
60
|
-
require 'ruote/exp/ro_persist'
|
61
85
|
require 'ruote/exp/ro_attributes'
|
62
|
-
require 'ruote/exp/ro_variables'
|
63
86
|
require 'ruote/exp/ro_filters'
|
87
|
+
require 'ruote/exp/ro_on_x'
|
88
|
+
require 'ruote/exp/ro_persist'
|
89
|
+
require 'ruote/exp/ro_timers'
|
90
|
+
require 'ruote/exp/ro_variables'
|
64
91
|
|
65
92
|
COMMON_ATT_KEYS = %w[
|
66
|
-
if unless
|
93
|
+
if unless
|
94
|
+
forget lose flank
|
95
|
+
timeout timers
|
96
|
+
on_error on_cancel on_timeout
|
97
|
+
]
|
67
98
|
|
68
|
-
attr_reader :context
|
69
99
|
attr_reader :h
|
70
100
|
|
71
101
|
h_reader :variables
|
@@ -79,6 +109,17 @@ module Ruote::Exp
|
|
79
109
|
h_reader :on_error
|
80
110
|
h_reader :on_cancel
|
81
111
|
h_reader :on_timeout
|
112
|
+
h_reader :on_terminate
|
113
|
+
|
114
|
+
attr_reader :context
|
115
|
+
|
116
|
+
# Mostly used when the expression is returned via Ruote::Engine#ps(wfid) or
|
117
|
+
# Ruote::Engine#processes(). If an error occurred for this flow expression,
|
118
|
+
# #ps will set this error field so that it yields the ProcessError.
|
119
|
+
#
|
120
|
+
# So, for short, usually, this attribute yields nil.
|
121
|
+
#
|
122
|
+
attr_accessor :error
|
82
123
|
|
83
124
|
def initialize(context, h)
|
84
125
|
|
@@ -99,13 +140,13 @@ module Ruote::Exp
|
|
99
140
|
h.on_cancel ||= attribute(:on_cancel)
|
100
141
|
h.on_error ||= attribute(:on_error)
|
101
142
|
h.on_timeout ||= attribute(:on_timeout)
|
143
|
+
h.on_terminate ||= attribute(:on_terminate)
|
102
144
|
end
|
103
145
|
|
104
146
|
def h=(hash)
|
147
|
+
|
105
148
|
@h = hash
|
106
|
-
class << h
|
107
|
-
include Ruote::HashDot
|
108
|
-
end
|
149
|
+
class << @h; include Ruote::HashDot; end
|
109
150
|
end
|
110
151
|
|
111
152
|
# Returns the Ruote::FlowExpressionId for this expression.
|
@@ -115,12 +156,22 @@ module Ruote::Exp
|
|
115
156
|
Ruote::FlowExpressionId.new(h.fei)
|
116
157
|
end
|
117
158
|
|
159
|
+
# Returns the workflow instance id of the workflow this expression
|
160
|
+
# belongs to.
|
161
|
+
#
|
162
|
+
def wfid
|
163
|
+
|
164
|
+
h.fei['wfid']
|
165
|
+
end
|
166
|
+
|
118
167
|
# Returns the Ruote::FlowExpressionIf of the parent expression, or nil
|
119
168
|
# if there is no parent expression.
|
120
169
|
#
|
121
170
|
def parent_id
|
122
171
|
|
123
|
-
h.parent_id ?
|
172
|
+
h.parent_id ?
|
173
|
+
Ruote::FlowExpressionId.new(h.parent_id) :
|
174
|
+
nil
|
124
175
|
end
|
125
176
|
|
126
177
|
# Fetches the parent expression, or returns nil if there is no parent
|
@@ -128,7 +179,34 @@ module Ruote::Exp
|
|
128
179
|
#
|
129
180
|
def parent
|
130
181
|
|
131
|
-
|
182
|
+
h.parent_id ?
|
183
|
+
Ruote::Exp::FlowExpression.fetch(@context, h.parent_id) :
|
184
|
+
nil
|
185
|
+
end
|
186
|
+
|
187
|
+
# Returns the root expression of this expression.
|
188
|
+
#
|
189
|
+
# The result is an instance of Ruote::FlowExpression or nil if the
|
190
|
+
# parent cannot be found.
|
191
|
+
#
|
192
|
+
def root
|
193
|
+
|
194
|
+
current = @h
|
195
|
+
exps = @context.storage.find_expressions(h.fei['wfid'])
|
196
|
+
|
197
|
+
while current && current['parent_id']
|
198
|
+
current = exps.find { |e| e['fei'] == current['parent_id'] }
|
199
|
+
end
|
200
|
+
|
201
|
+
current ? Ruote::Exp::FlowExpression.from_h(@context, current) : nil
|
202
|
+
end
|
203
|
+
|
204
|
+
# Returns the fei of the root expression of this expression.
|
205
|
+
# The result is an instance of Ruote::FlowExpressionId.
|
206
|
+
#
|
207
|
+
def root_id
|
208
|
+
|
209
|
+
root.fei
|
132
210
|
end
|
133
211
|
|
134
212
|
# Turns this FlowExpression instance into a Hash (well, just hands back
|
@@ -139,10 +217,19 @@ module Ruote::Exp
|
|
139
217
|
@h
|
140
218
|
end
|
141
219
|
|
220
|
+
# Returns a one-off Ruote::Workitem instance (the applied workitem).
|
221
|
+
#
|
222
|
+
def applied_workitem
|
223
|
+
|
224
|
+
@awi ||= Ruote::Workitem.new(h.applied_workitem)
|
225
|
+
end
|
226
|
+
|
142
227
|
# Instantiates expression back from hash.
|
143
228
|
#
|
144
229
|
def self.from_h(context, h)
|
145
230
|
|
231
|
+
return self.new(nil, h) unless context
|
232
|
+
|
146
233
|
exp_class = context.expmap.expression_class(h['name'])
|
147
234
|
|
148
235
|
exp_class.new(context, h)
|
@@ -182,8 +269,6 @@ module Ruote::Exp
|
|
182
269
|
fei = msg['fei']
|
183
270
|
action = msg['action']
|
184
271
|
|
185
|
-
p msg unless fei
|
186
|
-
|
187
272
|
if action == 'reply' && fei['engine_id'] != context.engine_id
|
188
273
|
#
|
189
274
|
# the reply has to go to another engine, let's locate the
|
@@ -206,14 +291,26 @@ module Ruote::Exp
|
|
206
291
|
|
207
292
|
fexp = nil
|
208
293
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
294
|
+
n = context.storage.class.name.match(/Couch/) ? 3 : 1
|
295
|
+
#
|
296
|
+
n.times do |i|
|
297
|
+
if fexp = fetch(context, msg['fei']); break; end
|
298
|
+
sleep 0.028 unless i == (n - 1)
|
213
299
|
end
|
214
|
-
#
|
300
|
+
#
|
301
|
+
# Simplify that once ruote-couch behaves
|
302
|
+
|
303
|
+
fexp.do(action, msg) if fexp
|
304
|
+
end
|
305
|
+
|
306
|
+
# Wraps a call to "apply", "reply", etc... Makes sure to set @msg
|
307
|
+
# with a deep copy of the msg before.
|
308
|
+
#
|
309
|
+
def do(action, msg)
|
310
|
+
|
311
|
+
@msg = Ruote.fulldup(msg)
|
215
312
|
|
216
|
-
|
313
|
+
send("do_#{action}", msg)
|
217
314
|
end
|
218
315
|
|
219
316
|
# Called by the worker when it has just created this FlowExpression and
|
@@ -221,34 +318,51 @@ module Ruote::Exp
|
|
221
318
|
#
|
222
319
|
def do_apply(msg)
|
223
320
|
|
224
|
-
|
321
|
+
unless Condition.apply?(attribute(:if), attribute(:unless))
|
322
|
+
|
323
|
+
return do_reply_to_parent(h.applied_workitem)
|
324
|
+
end
|
325
|
+
|
326
|
+
pi = h.parent_id
|
327
|
+
reply_immediately = false
|
225
328
|
|
226
|
-
if
|
329
|
+
if attribute(:scope).to_s == 'true'
|
227
330
|
|
228
|
-
|
331
|
+
h.variables ||= {}
|
229
332
|
end
|
230
333
|
|
231
334
|
if attribute(:forget).to_s == 'true'
|
232
335
|
|
233
|
-
pi = h.parent_id
|
234
|
-
wi = Ruote.fulldup(h.applied_workitem)
|
235
|
-
|
236
336
|
h.variables = compile_variables
|
237
337
|
h.parent_id = nil
|
238
338
|
h.forgotten = true
|
239
339
|
|
240
|
-
|
241
|
-
# reply to parent immediately (if there is a parent)
|
340
|
+
reply_immediately = true
|
242
341
|
|
243
342
|
elsif attribute(:lose).to_s == 'true'
|
244
343
|
|
245
344
|
h.lost = true
|
345
|
+
|
346
|
+
elsif msg['flanking'] or (attribute(:flank).to_s == 'true')
|
347
|
+
|
348
|
+
h.flanking = true
|
349
|
+
|
350
|
+
reply_immediately = true
|
351
|
+
end
|
352
|
+
|
353
|
+
if reply_immediately and pi
|
354
|
+
|
355
|
+
@context.storage.put_msg(
|
356
|
+
'reply',
|
357
|
+
'fei' => pi,
|
358
|
+
'workitem' => Ruote.fulldup(h.applied_workitem),
|
359
|
+
'flanking' => h.flanking)
|
246
360
|
end
|
247
361
|
|
248
362
|
filter
|
249
363
|
|
250
364
|
consider_tag
|
251
|
-
|
365
|
+
consider_timers
|
252
366
|
|
253
367
|
apply
|
254
368
|
end
|
@@ -257,50 +371,97 @@ module Ruote::Exp
|
|
257
371
|
# parent expression to take over (it will end up calling the #reply of
|
258
372
|
# the parent expression).
|
259
373
|
#
|
374
|
+
# Expression implementations are free to override this method.
|
375
|
+
# The common behaviour is in #do_reply_to_parent.
|
376
|
+
#
|
260
377
|
def reply_to_parent(workitem, delete=true)
|
261
378
|
|
262
|
-
|
263
|
-
|
264
|
-
if h.tagname
|
379
|
+
do_reply_to_parent(workitem, delete)
|
380
|
+
end
|
265
381
|
|
266
|
-
|
382
|
+
# The essence of the reply_to_parent job...
|
383
|
+
#
|
384
|
+
def do_reply_to_parent(workitem, delete=true)
|
267
385
|
|
268
|
-
|
386
|
+
# propagate the cancel "flavour" back, so that one can know
|
387
|
+
# why a branch got cancelled.
|
269
388
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
389
|
+
flavour = if @msg.nil?
|
390
|
+
nil
|
391
|
+
elsif @msg['action'] == 'cancel'
|
392
|
+
@msg['flavour'] || 'cancel'
|
393
|
+
elsif h.state.nil?
|
394
|
+
nil
|
395
|
+
else
|
396
|
+
@msg['flavour']
|
275
397
|
end
|
276
398
|
|
277
|
-
|
399
|
+
# deal with the timers and the schedules
|
278
400
|
|
279
|
-
|
401
|
+
%w[ timeout_schedule_id job_id ].each do |sid|
|
402
|
+
@context.storage.delete_schedule(h[sid]) if h[sid]
|
280
403
|
end
|
404
|
+
#
|
405
|
+
# legacy schedule ids, to be removed for ruote 2.4.0
|
406
|
+
|
407
|
+
@context.storage.delete_schedule(h.schedule_id) if h.schedule_id
|
408
|
+
#
|
409
|
+
# time-driven exps like cron, wait and once now all use h.schedule_id
|
410
|
+
|
411
|
+
h.timers.each do |schedule_id, action|
|
412
|
+
@context.storage.delete_schedule(schedule_id)
|
413
|
+
end if h.timers
|
414
|
+
|
415
|
+
# cancel flanking expressions if any
|
416
|
+
|
417
|
+
cancel_flanks(h.state == 'dying' ? 'kill' : nil)
|
281
418
|
|
282
|
-
|
419
|
+
# trigger or vanilla reply
|
420
|
+
|
421
|
+
if h.state == 'failing' # on_error is implicit (#do_fail got called)
|
283
422
|
|
284
423
|
trigger('on_error', workitem)
|
285
424
|
|
286
|
-
elsif h.state == 'cancelling'
|
425
|
+
elsif h.state == 'cancelling' && h.on_cancel
|
287
426
|
|
288
427
|
trigger('on_cancel', workitem)
|
289
428
|
|
290
|
-
elsif h.state == 'cancelling'
|
429
|
+
elsif h.state == 'cancelling' && h.on_re_apply
|
291
430
|
|
292
431
|
trigger('on_re_apply', workitem)
|
293
432
|
|
294
|
-
elsif h.state == 'timing_out'
|
433
|
+
elsif h.state == 'timing_out' && h.on_timeout
|
295
434
|
|
296
435
|
trigger('on_timeout', workitem)
|
297
436
|
|
298
|
-
elsif h.
|
437
|
+
elsif h.state == nil && h.on_reply
|
438
|
+
|
439
|
+
trigger('on_reply', workitem)
|
299
440
|
|
441
|
+
elsif (h.lost || h.flanking) && h.state.nil?
|
442
|
+
#
|
300
443
|
# do not reply, sit here (and wait for cancellation probably)
|
301
444
|
|
445
|
+
do_persist
|
446
|
+
|
447
|
+
elsif h.trigger && workitem['fields']["__#{h.trigger}__"]
|
448
|
+
#
|
449
|
+
# the "second take"
|
450
|
+
|
451
|
+
trigger(h.trigger, workitem)
|
452
|
+
|
302
453
|
else # vanilla reply
|
303
454
|
|
455
|
+
filter(workitem) if h.state.nil?
|
456
|
+
|
457
|
+
f = h.state.nil? && attribute(:vars_to_f)
|
458
|
+
Ruote.set(workitem['fields'], f, h.variables) if f
|
459
|
+
|
460
|
+
workitem['sub_wf_name'] = @h.applied_workitem['sub_wf_name']
|
461
|
+
workitem['sub_wf_revision'] = @h.applied_workitem['sub_wf_revision']
|
462
|
+
|
463
|
+
leave_tag(workitem) if h.tagname
|
464
|
+
|
304
465
|
(do_unpersist || return) if delete
|
305
466
|
# remove expression from storage
|
306
467
|
|
@@ -310,14 +471,30 @@ module Ruote::Exp
|
|
310
471
|
'reply',
|
311
472
|
'fei' => h.parent_id,
|
312
473
|
'workitem' => workitem.merge!('fei' => h.fei),
|
313
|
-
'updated_tree' => h.updated_tree
|
474
|
+
'updated_tree' => h.updated_tree, # nil most of the time
|
475
|
+
'flavour' => flavour)
|
476
|
+
|
314
477
|
else
|
315
478
|
|
316
479
|
@context.storage.put_msg(
|
317
480
|
h.forgotten ? 'ceased' : 'terminated',
|
318
481
|
'wfid' => h.fei['wfid'],
|
319
482
|
'fei' => h.fei,
|
320
|
-
'workitem' => workitem
|
483
|
+
'workitem' => workitem,
|
484
|
+
'variables' => h.variables,
|
485
|
+
'flavour' => flavour)
|
486
|
+
|
487
|
+
if h.state.nil? && h.on_terminate == 'regenerate' && ! h.forgotten
|
488
|
+
|
489
|
+
@context.storage.put_msg(
|
490
|
+
'regenerate',
|
491
|
+
'wfid' => h.fei['wfid'],
|
492
|
+
'tree' => h.original_tree,
|
493
|
+
'workitem' => workitem,
|
494
|
+
'variables' => h.variables,
|
495
|
+
'flavour' => flavour)
|
496
|
+
#'stash' =>
|
497
|
+
end
|
321
498
|
end
|
322
499
|
end
|
323
500
|
end
|
@@ -326,22 +503,37 @@ module Ruote::Exp
|
|
326
503
|
#
|
327
504
|
def do_reply(msg)
|
328
505
|
|
329
|
-
@msg = Ruote.fulldup(msg)
|
330
|
-
# keeping the message, for 'retry' in collision cases
|
331
|
-
|
332
506
|
workitem = msg['workitem']
|
333
507
|
fei = workitem['fei']
|
334
508
|
|
509
|
+
removed = h.children.delete(fei)
|
510
|
+
# accept without any check ?
|
511
|
+
|
512
|
+
if msg['flanking']
|
513
|
+
|
514
|
+
(h.flanks ||= []) << fei
|
515
|
+
|
516
|
+
if (not removed) # then it's a timer
|
517
|
+
|
518
|
+
do_persist
|
519
|
+
return
|
520
|
+
end
|
521
|
+
end
|
522
|
+
|
335
523
|
if ut = msg['updated_tree']
|
524
|
+
|
336
525
|
ct = tree.dup
|
337
526
|
ct.last[Ruote::FlowExpressionId.child_id(fei)] = ut
|
338
527
|
update_tree(ct)
|
339
528
|
end
|
340
529
|
|
341
|
-
h.
|
342
|
-
# accept without any check ?
|
530
|
+
if h.state == 'paused'
|
343
531
|
|
344
|
-
|
532
|
+
(h['paused_replies'] ||= []) << msg
|
533
|
+
|
534
|
+
do_persist
|
535
|
+
|
536
|
+
elsif h.state != nil # failing or timing out ...
|
345
537
|
|
346
538
|
if h.children.size < 1
|
347
539
|
reply_to_parent(workitem)
|
@@ -371,8 +563,6 @@ module Ruote::Exp
|
|
371
563
|
#
|
372
564
|
def do_cancel(msg)
|
373
565
|
|
374
|
-
@msg = Ruote.fulldup(msg)
|
375
|
-
|
376
566
|
flavour = msg['flavour']
|
377
567
|
|
378
568
|
return if h.state == 'cancelling' && flavour != 'kill'
|
@@ -381,42 +571,53 @@ module Ruote::Exp
|
|
381
571
|
return if h.state == 'failed' && flavour == 'timeout'
|
382
572
|
# do not timeout expressions that are "in error" (failed)
|
383
573
|
|
384
|
-
@msg = Ruote.fulldup(msg)
|
385
|
-
|
386
574
|
h.state = case flavour
|
387
575
|
when 'kill' then 'dying'
|
388
576
|
when 'timeout' then 'timing_out'
|
389
577
|
else 'cancelling'
|
390
578
|
end
|
391
579
|
|
392
|
-
h.
|
393
|
-
|
394
|
-
|
580
|
+
if h.state == 'timing_out'
|
581
|
+
|
582
|
+
h.applied_workitem['fields']['__timed_out__'] = [
|
583
|
+
h.fei, Ruote.now_to_utc_s, tree.first, compile_atts
|
584
|
+
]
|
395
585
|
|
396
|
-
|
586
|
+
elsif h.state == 'cancelling'
|
397
587
|
|
398
588
|
if t = msg['on_cancel']
|
399
589
|
|
400
590
|
h.on_cancel = t
|
401
591
|
|
402
|
-
elsif
|
592
|
+
elsif ra_opts = msg['re_apply']
|
403
593
|
|
404
|
-
|
594
|
+
ra_opts = {} if ra_opts == true
|
595
|
+
ra_opts['tree'] ||= tree
|
405
596
|
|
406
|
-
h.on_re_apply =
|
407
|
-
|
408
|
-
if fs = hra['fields']
|
409
|
-
h.applied_workitem['fields'] = fs
|
410
|
-
end
|
411
|
-
if mfs = hra['merge_in_fields']
|
412
|
-
h.applied_workitem['fields'].merge!(mfs)
|
413
|
-
end
|
597
|
+
h.on_re_apply = ra_opts
|
414
598
|
end
|
415
599
|
end
|
416
600
|
|
417
601
|
cancel(flavour)
|
418
602
|
end
|
419
603
|
|
604
|
+
# Emits a cancel message for each flanking expression (if any).
|
605
|
+
#
|
606
|
+
def cancel_flanks(flavour)
|
607
|
+
|
608
|
+
return unless h.flanks
|
609
|
+
|
610
|
+
h.flanks.each do |flank_fei|
|
611
|
+
|
612
|
+
@context.storage.put_msg(
|
613
|
+
'cancel',
|
614
|
+
'fei' => flank_fei,
|
615
|
+
'parent_id' => h.fei,
|
616
|
+
# indicating that this is a "cancel child", well...
|
617
|
+
'flavour' => flavour)
|
618
|
+
end
|
619
|
+
end
|
620
|
+
|
420
621
|
# This default implementation cancels all the [registered] children
|
421
622
|
# of this expression.
|
422
623
|
#
|
@@ -434,56 +635,84 @@ module Ruote::Exp
|
|
434
635
|
# if the do_persist returns false, it means it failed, implying this
|
435
636
|
# expression is stale, let's return, thus discarding this cancel message
|
436
637
|
|
437
|
-
children.each do |
|
638
|
+
children.each do |child_fei|
|
438
639
|
#
|
439
640
|
# let's send a cancel message to each of the children
|
440
641
|
#
|
441
642
|
# maybe some of them are gone or have not yet been applied, anyway,
|
442
|
-
# the
|
643
|
+
# the messages are sent
|
443
644
|
|
444
645
|
@context.storage.put_msg(
|
445
646
|
'cancel',
|
446
|
-
'fei' =>
|
647
|
+
'fei' => child_fei,
|
447
648
|
'parent_id' => h.fei, # indicating that this is a "cancel child"
|
448
649
|
'flavour' => flavour)
|
449
650
|
end
|
450
|
-
|
451
|
-
#if ! children.find { |i| Ruote::Exp::FlowExpression.fetch(@context, i) }
|
452
|
-
# #
|
453
|
-
# # since none of the children could be found in the storage right now,
|
454
|
-
# # it could mean that all children are already done or it could mean
|
455
|
-
# # that they are not yet applied...
|
456
|
-
# #
|
457
|
-
# # just to be sure let's send a new cancel message to this expression
|
458
|
-
# #
|
459
|
-
# # it's very important, since if there is no child to cancel the parent
|
460
|
-
# # the flow might get stuck here
|
461
|
-
# @context.storage.put_msg(
|
462
|
-
# 'cancel',
|
463
|
-
# 'fei' => h.fei,
|
464
|
-
# 'flavour' => flavour)
|
465
|
-
#end
|
466
651
|
end
|
467
652
|
|
468
653
|
# Called when handling an on_error, will place itself in a 'failing' state
|
469
654
|
# and cancel the children (when the reply from the children comes back,
|
470
|
-
# the
|
655
|
+
# the on_error will get triggered).
|
471
656
|
#
|
472
657
|
def do_fail(msg)
|
473
658
|
|
474
|
-
@msg = Ruote.fulldup(msg)
|
475
|
-
|
476
659
|
@h['state'] = 'failing'
|
477
660
|
@h['applied_workitem'] = msg['workitem']
|
478
661
|
|
479
662
|
if h.children.size < 1
|
663
|
+
|
480
664
|
reply_to_parent(@h['applied_workitem'])
|
665
|
+
|
481
666
|
else
|
667
|
+
|
668
|
+
flavour = msg['immediate'] ? 'kill' : nil
|
669
|
+
|
482
670
|
persist_or_raise
|
483
|
-
|
671
|
+
|
672
|
+
h.children.each do |i|
|
673
|
+
@context.storage.put_msg('cancel', 'fei' => i, 'flavour' => flavour)
|
674
|
+
end
|
484
675
|
end
|
485
676
|
end
|
486
677
|
|
678
|
+
# Expression received a "pause" message. Will put the expression in the
|
679
|
+
# "paused" state and then pass the message to the children.
|
680
|
+
#
|
681
|
+
# If the expression is in a non-nil state (failed, timed_out, ...), the
|
682
|
+
# message will be ignored.
|
683
|
+
#
|
684
|
+
def do_pause(msg)
|
685
|
+
|
686
|
+
return if h.state != nil
|
687
|
+
|
688
|
+
h['state'] = 'paused'
|
689
|
+
|
690
|
+
do_persist || return
|
691
|
+
|
692
|
+
h.children.each { |i|
|
693
|
+
@context.storage.put_msg('pause', 'fei' => i)
|
694
|
+
} unless msg['breakpoint']
|
695
|
+
end
|
696
|
+
|
697
|
+
# Will "unpause" the expression (if it was paused), and trigger any
|
698
|
+
# 'paused_replies' (replies that came while the expression was paused).
|
699
|
+
#
|
700
|
+
def do_resume(msg)
|
701
|
+
|
702
|
+
return if h.state != 'paused'
|
703
|
+
|
704
|
+
h['state'] = nil
|
705
|
+
replies = h.delete('paused_replies') || []
|
706
|
+
|
707
|
+
do_persist || return
|
708
|
+
|
709
|
+
h.children.each { |i| @context.storage.put_msg('resume', 'fei' => i) }
|
710
|
+
# resume children
|
711
|
+
|
712
|
+
replies.each { |m| @context.storage.put_msg(m.delete('action'), m) }
|
713
|
+
# trigger replies
|
714
|
+
end
|
715
|
+
|
487
716
|
#--
|
488
717
|
# misc
|
489
718
|
#++
|
@@ -524,77 +753,14 @@ module Ruote::Exp
|
|
524
753
|
#
|
525
754
|
def ancestor?(fei)
|
526
755
|
|
756
|
+
fei = fei.to_h if fei.respond_to?(:to_h)
|
757
|
+
|
527
758
|
return false unless h.parent_id
|
528
759
|
return true if h.parent_id == fei
|
529
760
|
|
530
761
|
parent.ancestor?(fei)
|
531
762
|
end
|
532
763
|
|
533
|
-
# Looks up "on_error" attribute
|
534
|
-
#
|
535
|
-
def lookup_on_error
|
536
|
-
|
537
|
-
if h.on_error
|
538
|
-
|
539
|
-
self
|
540
|
-
|
541
|
-
elsif h.parent_id
|
542
|
-
|
543
|
-
par = parent
|
544
|
-
# :( get_parent would probably be a better name for #parent
|
545
|
-
|
546
|
-
#if par.nil? && ($DEBUG || ARGV.include?('-d'))
|
547
|
-
# puts "~~"
|
548
|
-
# puts "parent gone for"
|
549
|
-
# puts "fei #{Ruote.sid(h.fei)}"
|
550
|
-
# puts "tree #{tree.inspect}"
|
551
|
-
# puts "replying to #{Ruote.sid(h.parent_id)}"
|
552
|
-
# puts "~~"
|
553
|
-
#end
|
554
|
-
# is sometimes helpful during debug sessions
|
555
|
-
|
556
|
-
par ? par.lookup_on_error : nil
|
557
|
-
|
558
|
-
else
|
559
|
-
|
560
|
-
nil
|
561
|
-
end
|
562
|
-
end
|
563
|
-
|
564
|
-
# Looks up parent with on_error attribute and triggers it
|
565
|
-
#
|
566
|
-
def handle_on_error(msg, error)
|
567
|
-
|
568
|
-
return false if h.state == 'failing'
|
569
|
-
|
570
|
-
oe_parent = lookup_on_error
|
571
|
-
|
572
|
-
return false unless oe_parent
|
573
|
-
# no parent with on_error attribute found
|
574
|
-
|
575
|
-
handler = oe_parent.on_error.to_s
|
576
|
-
|
577
|
-
return false if handler == ''
|
578
|
-
# empty on_error handler nullifies ancestor's on_error
|
579
|
-
|
580
|
-
workitem = msg['workitem']
|
581
|
-
|
582
|
-
workitem['fields']['__error__'] = {
|
583
|
-
'fei' => fei,
|
584
|
-
'at' => Ruote.now_to_utc_s,
|
585
|
-
'class' => error.class.to_s,
|
586
|
-
'message' => error.message,
|
587
|
-
'trace' => error.backtrace
|
588
|
-
}
|
589
|
-
|
590
|
-
@context.storage.put_msg(
|
591
|
-
'fail',
|
592
|
-
'fei' => oe_parent.h.fei,
|
593
|
-
'workitem' => workitem)
|
594
|
-
|
595
|
-
true # yes, error is being handled.
|
596
|
-
end
|
597
|
-
|
598
764
|
#--
|
599
765
|
# TREE
|
600
766
|
#++
|
@@ -603,6 +769,7 @@ module Ruote::Exp
|
|
603
769
|
# if it got updated.
|
604
770
|
#
|
605
771
|
def tree
|
772
|
+
|
606
773
|
h.updated_tree || h.original_tree
|
607
774
|
end
|
608
775
|
|
@@ -623,6 +790,7 @@ module Ruote::Exp
|
|
623
790
|
# seq.do_persist
|
624
791
|
#
|
625
792
|
def update_tree(t=nil)
|
793
|
+
|
626
794
|
h.updated_tree = t || Ruote.fulldup(h.original_tree)
|
627
795
|
end
|
628
796
|
|
@@ -728,102 +896,80 @@ module Ruote::Exp
|
|
728
896
|
#
|
729
897
|
def consider_tag
|
730
898
|
|
731
|
-
|
732
|
-
|
733
|
-
set_variable(h.tagname, h.fei)
|
899
|
+
tag = attribute(:tag)
|
734
900
|
|
735
|
-
|
901
|
+
return unless tag
|
736
902
|
|
737
|
-
|
738
|
-
|
739
|
-
'tag' => h.tagname,
|
740
|
-
'fei' => h.fei,
|
741
|
-
'workitem' => h.applied_workitem)
|
742
|
-
end
|
743
|
-
end
|
744
|
-
|
745
|
-
# Called by do_apply. Overriden in ParticipantExpression and RefExpression.
|
746
|
-
#
|
747
|
-
def consider_timeout
|
903
|
+
h.tagname = tag
|
904
|
+
h.full_tagname = applied_workitem.tags.join('/')
|
748
905
|
|
749
|
-
|
750
|
-
|
906
|
+
return if h.trigger
|
907
|
+
#
|
908
|
+
# do not consider tags when the tree is applied for an
|
909
|
+
# on_x trigger
|
751
910
|
|
752
|
-
|
753
|
-
# (ParticipantExpression).
|
754
|
-
#
|
755
|
-
def do_schedule_timeout(timeout)
|
911
|
+
h.full_tagname = (applied_workitem.tags + [ tag ]).join('/')
|
756
912
|
|
757
|
-
|
913
|
+
set_variable(h.tagname, h.fei)
|
914
|
+
set_variable('/' + h.full_tagname, h.fei)
|
758
915
|
|
759
|
-
|
916
|
+
applied_workitem.send(:add_tag, h.tagname)
|
760
917
|
|
761
|
-
|
762
|
-
'
|
763
|
-
h.
|
764
|
-
|
765
|
-
'action' => 'cancel',
|
918
|
+
@context.storage.put_msg(
|
919
|
+
'entered_tag',
|
920
|
+
'tag' => h.tagname,
|
921
|
+
'full_tag' => h.full_tagname,
|
766
922
|
'fei' => h.fei,
|
767
|
-
'
|
923
|
+
'workitem' => h.applied_workitem)
|
768
924
|
end
|
769
925
|
|
770
|
-
#
|
926
|
+
# Called when the expression is about to reply to its parent and wants
|
927
|
+
# to get rid of its tags.
|
771
928
|
#
|
772
|
-
def
|
773
|
-
|
774
|
-
# at first, nuke self
|
775
|
-
|
776
|
-
r = try_unpersist
|
929
|
+
def leave_tag(workitem)
|
777
930
|
|
778
|
-
|
779
|
-
"failed to remove exp to supplant "+
|
780
|
-
"#{Ruote.to_storage_id(h.fei)} #{tree.first}"
|
781
|
-
) if r.respond_to?(:keys)
|
931
|
+
unset_variable(h.tagname)
|
782
932
|
|
783
|
-
|
784
|
-
|
785
|
-
if t = opts['trigger']
|
786
|
-
tree[1]['_triggered'] = t.to_s
|
787
|
-
end
|
933
|
+
Ruote::Workitem.new(workitem).send(:remove_tag, h.tagname)
|
788
934
|
|
789
935
|
@context.storage.put_msg(
|
790
|
-
'
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
'variables' => h.variables
|
796
|
-
}.merge!(opts))
|
797
|
-
end
|
798
|
-
|
799
|
-
# 'on_{error|timeout|cancel|re_apply}' triggering
|
800
|
-
#
|
801
|
-
def trigger(on, workitem)
|
802
|
-
|
803
|
-
hon = h[on]
|
804
|
-
|
805
|
-
t = hon.is_a?(String) ? [ hon, {}, [] ] : hon
|
936
|
+
'left_tag',
|
937
|
+
'tag' => h.tagname,
|
938
|
+
'full_tag' => h.full_tagname,
|
939
|
+
'fei' => h.fei,
|
940
|
+
'workitem' => workitem)
|
806
941
|
|
807
|
-
|
942
|
+
return unless h.full_tagname # for backward compatibility
|
808
943
|
|
809
|
-
|
944
|
+
r = root
|
810
945
|
|
811
|
-
|
946
|
+
return unless r && r.variables # might happen
|
812
947
|
|
813
|
-
|
948
|
+
r.variables.delete(h.full_tagname)
|
814
949
|
|
815
|
-
|
816
|
-
reply_to_parent(workitem)
|
950
|
+
state = case (h.trigger || h.state)
|
817
951
|
|
818
|
-
|
819
|
-
|
952
|
+
when 'on_cancel' then 'cancelled'
|
953
|
+
when 'on_error' then 'failed'
|
954
|
+
when 'on_timeout' then 'timed out'
|
955
|
+
when 'on_re_apply' then nil
|
820
956
|
|
821
|
-
|
957
|
+
when 'cancelling' then 'cancelled'
|
958
|
+
when 'dying' then 'killed'
|
822
959
|
|
823
|
-
|
960
|
+
else nil
|
824
961
|
end
|
825
962
|
|
826
|
-
|
963
|
+
(r.variables['__past_tags__'] ||= []) << [
|
964
|
+
h.full_tagname,
|
965
|
+
fei.sid,
|
966
|
+
state,
|
967
|
+
Ruote.now_to_utc_s,
|
968
|
+
Ruote.fulldup(h.variables)
|
969
|
+
# not fullduping here triggers a segfault at some point with YAJL
|
970
|
+
]
|
971
|
+
|
972
|
+
r.do_persist unless r.fei == self.fei
|
827
973
|
end
|
828
974
|
end
|
829
975
|
end
|