ruote 2.2.0 → 2.3.0
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 +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
|
data/lib/ruote/util/time.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
|
|
@@ -50,7 +50,7 @@ module Ruote
|
|
|
50
50
|
"#{t.utc.strftime('%Y-%m-%d %H:%M:%S')}.#{sprintf('%06d', t.usec)} UTC"
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
-
# Returns a
|
|
53
|
+
# Returns a parseable representation of the UTC time now.
|
|
54
54
|
#
|
|
55
55
|
# like "2009/11/23 11:11:50.947109 UTC"
|
|
56
56
|
#
|
data/lib/ruote/util/tree.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
|
|
@@ -47,12 +47,74 @@ module Ruote
|
|
|
47
47
|
# # 0_0_0 alpha {}
|
|
48
48
|
# # 0_0_1 bravo {}
|
|
49
49
|
#
|
|
50
|
-
def
|
|
50
|
+
def self.tree_to_s(tree, expid='0')
|
|
51
51
|
|
|
52
52
|
d = expid.split('_').size - 1
|
|
53
53
|
s = "#{' ' * d * 2}#{expid} #{tree[0]} #{tree[1].inspect}\n"
|
|
54
54
|
tree[2].each_with_index { |t, i| s << tree_to_s(t, "#{expid}_#{i}") }
|
|
55
55
|
s
|
|
56
56
|
end
|
|
57
|
+
|
|
58
|
+
# Used by Ruote::ProcessStatus.
|
|
59
|
+
#
|
|
60
|
+
# Given a tree
|
|
61
|
+
#
|
|
62
|
+
# [ 'define', { 'name' => 'nada' }, [
|
|
63
|
+
# [ 'sequence', {}, [ [ 'alpha', {}, [] ], [ 'bravo', {}, [] ] ] ]
|
|
64
|
+
# ] ]
|
|
65
|
+
#
|
|
66
|
+
# will output something like
|
|
67
|
+
#
|
|
68
|
+
# { '0' => [ 'define', { 'name' => 'nada' } ],
|
|
69
|
+
# '0_0' => [ 'sequence', {} ],
|
|
70
|
+
# '0_0_0' => [ 'alpha', {} ],
|
|
71
|
+
# '0_0_1' => [ 'bravo', {} ] },
|
|
72
|
+
#
|
|
73
|
+
# An initial offset can be specifid with the 'pos' argument.
|
|
74
|
+
#
|
|
75
|
+
# Don't touch 'h', it's an accumulator.
|
|
76
|
+
#
|
|
77
|
+
def self.decompose_tree(t, pos='0', h={})
|
|
78
|
+
|
|
79
|
+
h[pos] = t[0, 2]
|
|
80
|
+
t[2].each_with_index { |c, i| decompose_tree(c, "#{pos}_#{i}", h) }
|
|
81
|
+
h
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Used by Ruote::ProcessStatus.
|
|
85
|
+
#
|
|
86
|
+
# Given a decomposed tree like
|
|
87
|
+
#
|
|
88
|
+
# { '0' => [ 'define', { 'name' => 'nada' } ],
|
|
89
|
+
# '0_0' => [ 'sequence', {} ],
|
|
90
|
+
# '0_0_0' => [ 'alpha', {} ],
|
|
91
|
+
# '0_0_1' => [ 'bravo', {} ] },
|
|
92
|
+
#
|
|
93
|
+
# will recompose it to
|
|
94
|
+
#
|
|
95
|
+
# [ 'define', { 'name' => 'nada' }, [
|
|
96
|
+
# [ 'sequence', {}, [ [ 'alpha', {}, [] ], [ 'bravo', {}, [] ] ] ]
|
|
97
|
+
# ] ]
|
|
98
|
+
#
|
|
99
|
+
# A starting point in the recomposition can be given with the 'pos' argument.
|
|
100
|
+
#
|
|
101
|
+
def self.recompose_tree(h, pos='0')
|
|
102
|
+
|
|
103
|
+
t = h[pos]
|
|
104
|
+
|
|
105
|
+
return nil unless t
|
|
106
|
+
|
|
107
|
+
t << []
|
|
108
|
+
i = 0
|
|
109
|
+
|
|
110
|
+
loop do
|
|
111
|
+
tt = recompose_tree(h, "#{pos}_#{i}")
|
|
112
|
+
break unless tt
|
|
113
|
+
t.last << tt
|
|
114
|
+
i = i + 1
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
t
|
|
118
|
+
end
|
|
57
119
|
end
|
|
58
120
|
|
data/lib/ruote/version.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
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
#++
|
|
24
24
|
|
|
25
25
|
module Ruote
|
|
26
|
-
|
|
26
|
+
|
|
27
|
+
VERSION = '2.3.0'
|
|
27
28
|
end
|
|
28
29
|
|
data/lib/ruote/worker.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
|
|
@@ -34,37 +34,56 @@ module Ruote
|
|
|
34
34
|
#
|
|
35
35
|
class Worker
|
|
36
36
|
|
|
37
|
-
EXP_ACTIONS = %w[ reply cancel fail receive dispatched ]
|
|
37
|
+
EXP_ACTIONS = %w[ reply cancel fail receive dispatched pause resume ]
|
|
38
38
|
# 'apply' is comprised in 'launch'
|
|
39
39
|
# 'receive' is a ParticipantExpression alias for 'reply'
|
|
40
40
|
|
|
41
|
-
PROC_ACTIONS = %w[
|
|
42
|
-
DISP_ACTIONS = %w[ dispatch dispatch_cancel ]
|
|
41
|
+
PROC_ACTIONS = %w[ cancel kill pause resume ].collect { |a| a + '_process' }
|
|
42
|
+
DISP_ACTIONS = %w[ dispatch dispatch_cancel dispatch_pause dispatch_resume ]
|
|
43
|
+
|
|
44
|
+
attr_reader :name
|
|
43
45
|
|
|
44
46
|
attr_reader :storage
|
|
45
47
|
attr_reader :context
|
|
46
48
|
|
|
49
|
+
attr_reader :state
|
|
47
50
|
attr_reader :run_thread
|
|
48
|
-
attr_reader :running
|
|
49
51
|
|
|
50
52
|
# Given a storage, creates a new instance of a Worker.
|
|
51
53
|
#
|
|
52
|
-
def initialize(storage)
|
|
54
|
+
def initialize(name, storage=nil)
|
|
55
|
+
|
|
56
|
+
if storage.nil?
|
|
57
|
+
storage = name
|
|
58
|
+
name = nil
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
@name = name || 'worker'
|
|
62
|
+
|
|
63
|
+
if storage.respond_to?(:storage)
|
|
64
|
+
@storage = storage.storage
|
|
65
|
+
@context = storage.context
|
|
66
|
+
else
|
|
67
|
+
@storage = storage
|
|
68
|
+
@context = Ruote::Context.new(storage)
|
|
69
|
+
end
|
|
53
70
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
# services like Logger to subscribe to the worker
|
|
71
|
+
service_name = @name
|
|
72
|
+
service_name << '_worker' unless service_name.match(/worker$/)
|
|
57
73
|
|
|
58
|
-
@
|
|
59
|
-
@context = Ruote::Context.new(storage, self)
|
|
74
|
+
@context.add_service(service_name, self)
|
|
60
75
|
|
|
61
76
|
@last_time = Time.at(0.0).utc # 1970...
|
|
62
77
|
|
|
63
|
-
@
|
|
78
|
+
@state = 'running'
|
|
64
79
|
@run_thread = nil
|
|
80
|
+
@state_mutex = Mutex.new
|
|
65
81
|
|
|
66
82
|
@msgs = []
|
|
67
|
-
|
|
83
|
+
|
|
84
|
+
@sleep_time = @context['restless_worker'] ? nil : 0.000
|
|
85
|
+
|
|
86
|
+
@info = @context['worker_info_enabled'] == false ? nil : Info.new(self)
|
|
68
87
|
end
|
|
69
88
|
|
|
70
89
|
# Runs the worker in the current thread. See #run_in_thread for running
|
|
@@ -72,19 +91,19 @@ module Ruote
|
|
|
72
91
|
#
|
|
73
92
|
def run
|
|
74
93
|
|
|
75
|
-
step while @
|
|
94
|
+
step while @state != 'stopped'
|
|
76
95
|
end
|
|
77
96
|
|
|
78
97
|
# Triggers the run method of the worker in a dedicated thread.
|
|
79
98
|
#
|
|
80
99
|
def run_in_thread
|
|
81
100
|
|
|
82
|
-
Thread.abort_on_exception = true
|
|
83
|
-
# TODO : remove me at some point
|
|
101
|
+
#Thread.abort_on_exception = true
|
|
84
102
|
|
|
85
|
-
@
|
|
103
|
+
@state = 'running'
|
|
86
104
|
|
|
87
105
|
@run_thread = Thread.new { run }
|
|
106
|
+
@run_thread['ruote_worker'] = self
|
|
88
107
|
end
|
|
89
108
|
|
|
90
109
|
# Joins the run thread of this worker (if there is no such thread, this
|
|
@@ -92,15 +111,7 @@ module Ruote
|
|
|
92
111
|
#
|
|
93
112
|
def join
|
|
94
113
|
|
|
95
|
-
@run_thread.join
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
# Loggers and trackers call this method when subscribing for events /
|
|
99
|
-
# actions in this worker.
|
|
100
|
-
#
|
|
101
|
-
def subscribe(actions, subscriber)
|
|
102
|
-
|
|
103
|
-
@subscribers << [ actions, subscriber ]
|
|
114
|
+
@run_thread.join rescue nil
|
|
104
115
|
end
|
|
105
116
|
|
|
106
117
|
# Shuts down this worker (makes sure it won't fetch further messages
|
|
@@ -108,12 +119,9 @@ module Ruote
|
|
|
108
119
|
#
|
|
109
120
|
def shutdown
|
|
110
121
|
|
|
111
|
-
@
|
|
122
|
+
@state_mutex.synchronize { @state = 'stopped' }
|
|
112
123
|
|
|
113
|
-
|
|
114
|
-
@run_thread.join
|
|
115
|
-
rescue Exception => e
|
|
116
|
-
end
|
|
124
|
+
join
|
|
117
125
|
end
|
|
118
126
|
|
|
119
127
|
# Returns true if the engine system is inactive, ie if all the process
|
|
@@ -144,70 +152,192 @@ module Ruote
|
|
|
144
152
|
|
|
145
153
|
protected
|
|
146
154
|
|
|
147
|
-
#
|
|
148
|
-
# came, then fetches msgs and processes them.
|
|
155
|
+
# If worker_state_enabled is set, check for a potential new state.
|
|
149
156
|
#
|
|
150
|
-
def
|
|
157
|
+
def determine_state
|
|
158
|
+
|
|
159
|
+
@state_mutex.synchronize do
|
|
160
|
+
|
|
161
|
+
@state = (
|
|
162
|
+
@storage.get('variables', 'worker') || { 'state' => 'running' }
|
|
163
|
+
)['state'] if @state != 'stopped' && @context['worker_state_enabled']
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Gets schedules from the storage and if their time has come,
|
|
168
|
+
# turns them into msg (for immediate execution).
|
|
169
|
+
#
|
|
170
|
+
def process_schedules
|
|
151
171
|
|
|
152
172
|
now = Time.now.utc
|
|
153
173
|
delta = now - @last_time
|
|
154
174
|
|
|
155
|
-
if delta
|
|
175
|
+
return if delta < 0.8
|
|
156
176
|
#
|
|
157
|
-
# at most
|
|
177
|
+
# consider schedules at most twice per second (don't do that job
|
|
178
|
+
# too often)
|
|
158
179
|
|
|
159
|
-
|
|
180
|
+
@last_time = now
|
|
160
181
|
|
|
161
|
-
|
|
162
|
-
|
|
182
|
+
@storage.get_schedules(delta, now).each { |s| turn_schedule_to_msg(s) }
|
|
183
|
+
end
|
|
163
184
|
|
|
164
|
-
|
|
185
|
+
# Gets msgs from the storage (if needed) and processes them one by one.
|
|
186
|
+
#
|
|
187
|
+
def process_msgs
|
|
165
188
|
|
|
166
189
|
@msgs = @storage.get_msgs if @msgs.empty?
|
|
167
190
|
|
|
168
|
-
processed = 0
|
|
169
191
|
collisions = 0
|
|
170
192
|
|
|
171
|
-
while msg = @msgs.shift
|
|
193
|
+
while @msg = @msgs.shift
|
|
172
194
|
|
|
173
|
-
r = process(msg)
|
|
195
|
+
r = process(@msg)
|
|
174
196
|
|
|
175
197
|
if r != false
|
|
176
|
-
|
|
198
|
+
@processed_msgs += 1
|
|
177
199
|
else
|
|
178
200
|
collisions += 1
|
|
179
201
|
end
|
|
180
202
|
|
|
181
203
|
if collisions > 2
|
|
182
204
|
@msgs = @msgs[(@msgs.size / 2)..-1] || []
|
|
205
|
+
collisions = 0
|
|
183
206
|
end
|
|
184
207
|
|
|
185
|
-
|
|
208
|
+
break if Time.now.utc - @last_time >= 0.8
|
|
209
|
+
end
|
|
210
|
+
end
|
|
186
211
|
|
|
187
|
-
|
|
212
|
+
# Some storage implementations cache information before a step
|
|
213
|
+
# begins, reducing the number of requests to the underlying
|
|
214
|
+
# data system. This begin step notifies the storage that
|
|
215
|
+
# a new step is on and it should refresh the cached information.
|
|
216
|
+
#
|
|
217
|
+
# The storage implementation, if it supports this feature, will cache
|
|
218
|
+
# the information in the thread local info.
|
|
219
|
+
#
|
|
220
|
+
def begin_step
|
|
188
221
|
|
|
189
|
-
|
|
222
|
+
Thread.current['ruote_worker'] = self
|
|
223
|
+
|
|
224
|
+
@storage.begin_step if @storage.respond_to?(:begin_step)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# One worker step, fetches schedules and triggers those whose time has
|
|
228
|
+
# came, then fetches msgs and processes them.
|
|
229
|
+
#
|
|
230
|
+
def step
|
|
231
|
+
|
|
232
|
+
begin_step
|
|
233
|
+
|
|
234
|
+
@msg = nil
|
|
235
|
+
@processed_msgs = 0
|
|
236
|
+
|
|
237
|
+
determine_state
|
|
238
|
+
|
|
239
|
+
if @state == 'stopped'
|
|
240
|
+
return
|
|
241
|
+
elsif @state == 'running'
|
|
242
|
+
process_schedules
|
|
243
|
+
process_msgs
|
|
190
244
|
end
|
|
191
245
|
|
|
192
|
-
#
|
|
246
|
+
take_a_rest # 'running' or 'paused'
|
|
247
|
+
|
|
248
|
+
rescue => err
|
|
249
|
+
|
|
250
|
+
handle_step_error(err, @msg) # msg may be nil
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# This default implementation dumps error information to $stderr as
|
|
254
|
+
# soon as #step intercepts the error.
|
|
255
|
+
#
|
|
256
|
+
# Normally such information should only appear when developing a
|
|
257
|
+
# storage, the information here is thus helpful for storage developers.
|
|
258
|
+
# If such info is emitted in production or in application development,
|
|
259
|
+
# you should pass the info to the storage developer/maintainer.
|
|
260
|
+
#
|
|
261
|
+
# Feel free to override this method if you need it to output to
|
|
262
|
+
# a channel different than $stderr (or rebind $stderr).
|
|
263
|
+
#
|
|
264
|
+
# The second parameter is "msg", if the error occured while processing a
|
|
265
|
+
# msg, then this message is passed to handle_step_error. msg will be
|
|
266
|
+
# nil if the error occurred while doing get_msgs or get_schedules.
|
|
267
|
+
#
|
|
268
|
+
def handle_step_error(err, msg)
|
|
269
|
+
|
|
270
|
+
$stderr.puts '#' * 80
|
|
271
|
+
$stderr.puts
|
|
272
|
+
$stderr.puts '** worker#step intercepted exception **'
|
|
273
|
+
$stderr.puts
|
|
274
|
+
$stderr.puts "Please report issue or fix your #{@storage.class} impl,"
|
|
275
|
+
$stderr.puts
|
|
276
|
+
$stderr.puts "or override Ruote::Worker#handle_step_error(e, msg) so that"
|
|
277
|
+
$stderr.puts "the issue is dealt with appropriately. For example:"
|
|
278
|
+
$stderr.puts
|
|
279
|
+
$stderr.puts " class Ruote::Worker"
|
|
280
|
+
$stderr.puts " def handle_step_error(e, msg)"
|
|
281
|
+
$stderr.puts " logger.error('ruote step error: ' + e.inspect)"
|
|
282
|
+
$stderr.puts " mailer.send_error('admin@acme.com', e)"
|
|
283
|
+
$stderr.puts " end"
|
|
284
|
+
$stderr.puts " end"
|
|
285
|
+
$stderr.puts
|
|
286
|
+
$stderr.puts '# ' * 40
|
|
287
|
+
$stderr.puts
|
|
288
|
+
$stderr.puts 'error class/message/backtrace:'
|
|
289
|
+
$stderr.puts err.class.name
|
|
290
|
+
$stderr.puts err.message.inspect
|
|
291
|
+
$stderr.puts *err.backtrace
|
|
292
|
+
$stderr.puts err.details if err.respond_to?(:details)
|
|
293
|
+
$stderr.puts
|
|
294
|
+
$stderr.puts 'msg:'
|
|
295
|
+
if msg && msg.is_a?(Hash)
|
|
296
|
+
$stderr.puts msg.select { |k, v|
|
|
297
|
+
%w[ action wfid fei ].include?(k)
|
|
298
|
+
}.inspect
|
|
299
|
+
else
|
|
300
|
+
$stderr.puts msg.inspect
|
|
301
|
+
end
|
|
302
|
+
$stderr.puts
|
|
303
|
+
$stderr.puts '#' * 80
|
|
304
|
+
|
|
305
|
+
$stderr.flush
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
# In order not to hammer the storage for msgs too much, take a rest.
|
|
309
|
+
#
|
|
310
|
+
# If the number of processed messages is more than zero, there are probably
|
|
311
|
+
# more msgs coming, no time for a rest...
|
|
312
|
+
#
|
|
313
|
+
# If @sleep_time is nil (restless_worker option set to true), the worker
|
|
314
|
+
# will never rest.
|
|
315
|
+
#
|
|
316
|
+
def take_a_rest
|
|
317
|
+
|
|
318
|
+
return if @sleep_time == nil
|
|
319
|
+
|
|
320
|
+
if @processed_msgs < 1
|
|
193
321
|
|
|
194
|
-
if processed == 0
|
|
195
322
|
@sleep_time += 0.001
|
|
196
323
|
@sleep_time = 0.499 if @sleep_time > 0.499
|
|
324
|
+
|
|
197
325
|
sleep(@sleep_time)
|
|
326
|
+
|
|
198
327
|
else
|
|
328
|
+
|
|
199
329
|
@sleep_time = 0.000
|
|
200
330
|
end
|
|
201
331
|
end
|
|
202
332
|
|
|
203
333
|
# Given a schedule, attempts to trigger it.
|
|
204
334
|
#
|
|
205
|
-
# It first tries to
|
|
206
|
-
#
|
|
207
|
-
#
|
|
208
|
-
#
|
|
335
|
+
# It first tries to reserve the schedule. If the reservation fails
|
|
336
|
+
# (another worker was successful probably), false is returned.
|
|
337
|
+
# The schedule is triggered if the reservation was successful, true
|
|
338
|
+
# is returned.
|
|
209
339
|
#
|
|
210
|
-
def
|
|
340
|
+
def turn_schedule_to_msg(schedule)
|
|
211
341
|
|
|
212
342
|
msg = Ruote.fulldup(schedule['msg'])
|
|
213
343
|
|
|
@@ -234,51 +364,66 @@ module Ruote
|
|
|
234
364
|
|
|
235
365
|
begin
|
|
236
366
|
|
|
237
|
-
|
|
367
|
+
@context.pre_notify(msg)
|
|
368
|
+
|
|
369
|
+
case msg['action']
|
|
370
|
+
|
|
371
|
+
when 'launch', 'apply', 'regenerate'
|
|
372
|
+
|
|
373
|
+
launch(msg)
|
|
238
374
|
|
|
239
|
-
|
|
240
|
-
#
|
|
241
|
-
# warning here, it could be a reply, with a 'tree' key...
|
|
375
|
+
when *EXP_ACTIONS
|
|
242
376
|
|
|
243
|
-
|
|
377
|
+
Ruote::Exp::FlowExpression.do_action(@context, msg)
|
|
244
378
|
|
|
245
|
-
|
|
379
|
+
when *DISP_ACTIONS
|
|
246
380
|
|
|
247
|
-
|
|
381
|
+
@context.dispatch_pool.handle(msg)
|
|
248
382
|
|
|
249
|
-
|
|
383
|
+
when *PROC_ACTIONS
|
|
250
384
|
|
|
251
|
-
|
|
385
|
+
self.send(msg['action'], msg)
|
|
252
386
|
|
|
253
|
-
|
|
387
|
+
when 'reput'
|
|
254
388
|
|
|
255
|
-
|
|
389
|
+
reput(msg)
|
|
256
390
|
|
|
257
|
-
|
|
258
|
-
|
|
391
|
+
when 'raise'
|
|
392
|
+
|
|
393
|
+
handle_msg_error(msg['msg'], msg['error'])
|
|
394
|
+
|
|
395
|
+
when 'respark'
|
|
396
|
+
|
|
397
|
+
respark(msg)
|
|
398
|
+
|
|
399
|
+
#else
|
|
400
|
+
# no special processing required for message, let it pass
|
|
401
|
+
# to the subscribers (the notify two lines after)
|
|
259
402
|
end
|
|
260
403
|
|
|
261
|
-
notify(msg)
|
|
404
|
+
@context.notify(msg)
|
|
405
|
+
# notify subscribers of successfully processed msgs
|
|
262
406
|
|
|
263
|
-
rescue =>
|
|
407
|
+
rescue => err
|
|
264
408
|
|
|
265
|
-
|
|
409
|
+
handle_msg_error(msg, err)
|
|
266
410
|
end
|
|
267
411
|
|
|
412
|
+
@context.storage.done(msg) if @context.storage.respond_to?(:done)
|
|
413
|
+
|
|
414
|
+
@info << msg if @info
|
|
415
|
+
# for the stats
|
|
416
|
+
|
|
268
417
|
true
|
|
269
418
|
end
|
|
270
419
|
|
|
271
|
-
#
|
|
272
|
-
# interested in the kind of action the msg ordered.
|
|
420
|
+
# Passes the msg and the err it resulted in to the error_handler.
|
|
273
421
|
#
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
422
|
+
# Some storage/worker implementation may want to override this.
|
|
423
|
+
#
|
|
424
|
+
def handle_msg_error(msg, err)
|
|
277
425
|
|
|
278
|
-
|
|
279
|
-
subscriber.notify(msg)
|
|
280
|
-
end
|
|
281
|
-
end
|
|
426
|
+
@context.error_handler.msg_handle(msg, err)
|
|
282
427
|
end
|
|
283
428
|
|
|
284
429
|
# Works for both the 'launch' and the 'apply' msgs.
|
|
@@ -290,24 +435,43 @@ module Ruote
|
|
|
290
435
|
|
|
291
436
|
tree = msg['tree']
|
|
292
437
|
variables = msg['variables']
|
|
438
|
+
wi = msg['workitem']
|
|
293
439
|
|
|
294
440
|
exp_class = @context.expmap.expression_class(tree.first)
|
|
295
441
|
|
|
296
442
|
# msg['wfid'] only : it's a launch
|
|
297
443
|
# msg['fei'] : it's a sub launch (a supplant ?)
|
|
298
444
|
|
|
445
|
+
if is_launch?(msg, exp_class)
|
|
446
|
+
|
|
447
|
+
name = tree[1]['name'] || tree[1].keys.find { |k| tree[1][k] == nil }
|
|
448
|
+
revision = tree[1]['revision'] || tree[1]['rev']
|
|
449
|
+
|
|
450
|
+
wi['wf_name'] ||= name
|
|
451
|
+
wi['wf_revision'] ||= revision
|
|
452
|
+
wi['wf_launched_at'] ||= Ruote.now_to_utc_s
|
|
453
|
+
|
|
454
|
+
wi['sub_wf_name'] = name
|
|
455
|
+
wi['sub_wf_revision'] = revision
|
|
456
|
+
wi['sub_wf_launched_at'] = Ruote.now_to_utc_s
|
|
457
|
+
end
|
|
458
|
+
|
|
299
459
|
exp_hash = {
|
|
300
460
|
'fei' => msg['fei'] || {
|
|
301
461
|
'engine_id' => @context.engine_id,
|
|
302
462
|
'wfid' => msg['wfid'],
|
|
303
463
|
'subid' => Ruote.generate_subid(msg.inspect),
|
|
304
|
-
'expid' => '0' },
|
|
464
|
+
'expid' => msg['expid'] || '0' },
|
|
305
465
|
'parent_id' => msg['parent_id'],
|
|
306
|
-
'original_tree' => tree,
|
|
307
466
|
'variables' => variables,
|
|
308
|
-
'applied_workitem' =>
|
|
309
|
-
'forgotten' => msg['forgotten']
|
|
310
|
-
|
|
467
|
+
'applied_workitem' => wi,
|
|
468
|
+
'forgotten' => msg['forgotten'],
|
|
469
|
+
'lost' => msg['lost'],
|
|
470
|
+
'flanking' => msg['flanking'],
|
|
471
|
+
'stash' => msg['stash'],
|
|
472
|
+
'trigger' => msg['trigger'],
|
|
473
|
+
'on_reply' => msg['on_reply'],
|
|
474
|
+
'supplanted' => msg['supplanted'] }
|
|
311
475
|
|
|
312
476
|
if not exp_class
|
|
313
477
|
|
|
@@ -320,19 +484,30 @@ module Ruote
|
|
|
320
484
|
exp_class = Ruote::Exp::SequenceExpression
|
|
321
485
|
end
|
|
322
486
|
|
|
323
|
-
|
|
487
|
+
exp_hash = exp_hash.reject { |k, v| v.nil? }
|
|
488
|
+
# compact nils away
|
|
489
|
+
|
|
490
|
+
exp_hash['original_tree'] = tree
|
|
491
|
+
# keep track of original tree
|
|
492
|
+
|
|
493
|
+
exp = exp_class.new(@context, exp_hash)
|
|
324
494
|
|
|
325
495
|
exp.initial_persist
|
|
326
|
-
exp.
|
|
496
|
+
exp.do(:apply, msg)
|
|
327
497
|
end
|
|
328
498
|
|
|
329
499
|
# Returns true if the msg is a "launch" (ie not a simply "apply").
|
|
330
500
|
#
|
|
331
501
|
def is_launch?(msg, exp_class)
|
|
332
502
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
(msg['
|
|
503
|
+
if exp_class != Ruote::Exp::DefineExpression
|
|
504
|
+
false
|
|
505
|
+
elsif %w[ launch regenerate ].include?(msg['action'])
|
|
506
|
+
true
|
|
507
|
+
else
|
|
508
|
+
(msg['trigger'] == 'on_re_apply')
|
|
509
|
+
# let re-apply "define" blocks, as in Ruote.define {}
|
|
510
|
+
end
|
|
336
511
|
end
|
|
337
512
|
|
|
338
513
|
# Handles a 'cancel_process' msg (translates it into a "cancel root
|
|
@@ -346,16 +521,170 @@ module Ruote
|
|
|
346
521
|
|
|
347
522
|
return unless root
|
|
348
523
|
|
|
349
|
-
flavour = (msg['action'] == 'kill_process') ? 'kill' : nil
|
|
350
|
-
|
|
351
524
|
@storage.put_msg(
|
|
352
525
|
'cancel',
|
|
353
526
|
'fei' => root['fei'],
|
|
354
527
|
'wfid' => msg['wfid'], # indicates this was triggered by cancel_process
|
|
355
|
-
'flavour' => flavour)
|
|
528
|
+
'flavour' => msg['flavour'])
|
|
356
529
|
end
|
|
357
530
|
|
|
358
531
|
alias kill_process cancel_process
|
|
532
|
+
|
|
533
|
+
# Handles 'pause_process' and 'resume_process'.
|
|
534
|
+
#
|
|
535
|
+
def pause_process(msg)
|
|
536
|
+
|
|
537
|
+
root = @storage.find_root_expression(msg['wfid'])
|
|
538
|
+
|
|
539
|
+
return unless root
|
|
540
|
+
|
|
541
|
+
@storage.put_msg(
|
|
542
|
+
msg['action'] == 'pause_process' ? 'pause' : 'resume',
|
|
543
|
+
'fei' => root['fei'],
|
|
544
|
+
'wfid' => msg['wfid']) # it was triggered by {pause|resume}_process
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
alias resume_process pause_process
|
|
548
|
+
|
|
549
|
+
# Reputs a doc or a msg.
|
|
550
|
+
#
|
|
551
|
+
# Used by certain storage implementations to pass documents around workers
|
|
552
|
+
# or to reschedule msgs (see ruote-swf).
|
|
553
|
+
#
|
|
554
|
+
def reput(msg)
|
|
555
|
+
|
|
556
|
+
if doc = msg['doc']
|
|
557
|
+
|
|
558
|
+
r = @storage.put(doc)
|
|
559
|
+
|
|
560
|
+
return unless r.is_a?(Hash)
|
|
561
|
+
|
|
562
|
+
doc['_rev'] = r['_rev']
|
|
563
|
+
|
|
564
|
+
reput(msg)
|
|
565
|
+
|
|
566
|
+
elsif msg = msg['msg']
|
|
567
|
+
|
|
568
|
+
@storage.put_msg(msg['action'], msg)
|
|
569
|
+
end
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
# This action resparks a stalled workflow instance. It's usually
|
|
573
|
+
# triggered via Dashboard#respark
|
|
574
|
+
#
|
|
575
|
+
# It's been made into a msg (worker action) in order to facilitate
|
|
576
|
+
# migration tooling (ruote-swf for example).
|
|
577
|
+
#
|
|
578
|
+
def respark(msg)
|
|
579
|
+
|
|
580
|
+
wfid = msg['wfid']
|
|
581
|
+
opts = msg['respark']
|
|
582
|
+
|
|
583
|
+
ps = ProcessStatus.fetch(@context, [ wfid ], {}).first
|
|
584
|
+
|
|
585
|
+
error_feis = ps.errors.collect(&:fei)
|
|
586
|
+
errors_too = !! opts['errors_too']
|
|
587
|
+
|
|
588
|
+
ps.leaves.each do |fexp|
|
|
589
|
+
|
|
590
|
+
next if errors_too == false && error_feis.include?(fexp.fei)
|
|
591
|
+
|
|
592
|
+
@context.storage.put_msg(
|
|
593
|
+
'cancel', 'fei' => fexp.fei.h, 're_apply' => {})
|
|
594
|
+
end
|
|
595
|
+
end
|
|
596
|
+
|
|
597
|
+
#
|
|
598
|
+
# Gathering stats about this worker.
|
|
599
|
+
#
|
|
600
|
+
# Those stats can then be obtained via Dashboard#worker_info
|
|
601
|
+
# (Engine#worker_info).
|
|
602
|
+
#
|
|
603
|
+
class Info
|
|
604
|
+
|
|
605
|
+
def initialize(worker)
|
|
606
|
+
|
|
607
|
+
@worker = worker
|
|
608
|
+
@ip = Ruote.local_ip
|
|
609
|
+
@hostname = Socket.gethostname
|
|
610
|
+
@system = `uname -a`.strip rescue nil
|
|
611
|
+
|
|
612
|
+
@since = Time.now
|
|
613
|
+
@msgs = []
|
|
614
|
+
@last_save = Time.now - 2 * 60
|
|
615
|
+
end
|
|
616
|
+
|
|
617
|
+
def <<(msg)
|
|
618
|
+
|
|
619
|
+
if msg['put_at'].nil?
|
|
620
|
+
puts '-' * 80
|
|
621
|
+
puts "msg missing 'put_at':"
|
|
622
|
+
pp msg
|
|
623
|
+
puts '-' * 80
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
@msgs << {
|
|
627
|
+
'processed_at' => Ruote.now_to_utc_s,
|
|
628
|
+
'wait_time' => Time.now - Time.parse(msg['put_at'])
|
|
629
|
+
#'action' => msg['action']
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
save if Time.now > @last_save + 60
|
|
633
|
+
end
|
|
634
|
+
|
|
635
|
+
protected
|
|
636
|
+
|
|
637
|
+
def save
|
|
638
|
+
|
|
639
|
+
doc = @worker.storage.get('variables', 'workers') || {}
|
|
640
|
+
|
|
641
|
+
doc['type'] = 'variables'
|
|
642
|
+
doc['_id'] = 'workers'
|
|
643
|
+
|
|
644
|
+
now = Time.now
|
|
645
|
+
|
|
646
|
+
@msgs = @msgs.drop_while { |msg|
|
|
647
|
+
Time.parse(msg['processed_at']) < now - 3600
|
|
648
|
+
}
|
|
649
|
+
mm = @msgs.drop_while { |msg|
|
|
650
|
+
Time.parse(msg['processed_at']) < now - 60
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
hour_count = @msgs.size < 1 ? 1 : @msgs.size
|
|
654
|
+
minute_count = mm.size < 1 ? 1 : mm.size
|
|
655
|
+
|
|
656
|
+
key = [
|
|
657
|
+
@worker.name, @ip.gsub(/\./, '_'), $$.to_s
|
|
658
|
+
].join('/')
|
|
659
|
+
|
|
660
|
+
(doc['workers'] ||= {})[key] = {
|
|
661
|
+
|
|
662
|
+
'class' => @worker.class.to_s,
|
|
663
|
+
'name' => @name,
|
|
664
|
+
'ip' => @ip,
|
|
665
|
+
'hostname' => @hostname,
|
|
666
|
+
'pid' => $$,
|
|
667
|
+
'system' => @system,
|
|
668
|
+
'put_at' => Ruote.now_to_utc_s,
|
|
669
|
+
'uptime' => Time.now - @since,
|
|
670
|
+
|
|
671
|
+
'processed_last_minute' =>
|
|
672
|
+
minute_count,
|
|
673
|
+
'wait_time_last_minute' =>
|
|
674
|
+
mm.inject(0.0) { |s, m| s + m['wait_time'] } / minute_count.to_f,
|
|
675
|
+
'processed_last_hour' =>
|
|
676
|
+
hour_count,
|
|
677
|
+
'wait_time_last_hour' =>
|
|
678
|
+
@msgs.inject(0.0) { |s, m| s + m['wait_time'] } / hour_count.to_f
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
r = @worker.storage.put(doc)
|
|
682
|
+
|
|
683
|
+
@last_save = Time.now
|
|
684
|
+
|
|
685
|
+
save if r != nil
|
|
686
|
+
end
|
|
687
|
+
end
|
|
359
688
|
end
|
|
360
689
|
end
|
|
361
690
|
|