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.
Files changed (305) hide show
  1. data/CHANGELOG.txt +166 -1
  2. data/CREDITS.txt +36 -17
  3. data/LICENSE.txt +1 -1
  4. data/README.rdoc +1 -7
  5. data/Rakefile +38 -29
  6. data/TODO.txt +93 -52
  7. data/lib/ruote-fs.rb +3 -0
  8. data/lib/ruote.rb +5 -1
  9. data/lib/ruote/context.rb +140 -35
  10. data/lib/ruote/dashboard.rb +1247 -0
  11. data/lib/ruote/{engine → dboard}/process_error.rb +22 -2
  12. data/lib/ruote/dboard/process_status.rb +587 -0
  13. data/lib/ruote/engine.rb +6 -871
  14. data/lib/ruote/exp/command.rb +7 -2
  15. data/lib/ruote/exp/commanded.rb +2 -2
  16. data/lib/ruote/exp/condition.rb +38 -13
  17. data/lib/ruote/exp/fe_add_branches.rb +1 -1
  18. data/lib/ruote/exp/fe_apply.rb +1 -1
  19. data/lib/ruote/exp/fe_await.rb +357 -0
  20. data/lib/ruote/exp/fe_cancel_process.rb +17 -3
  21. data/lib/ruote/exp/fe_command.rb +8 -4
  22. data/lib/ruote/exp/fe_concurrence.rb +218 -18
  23. data/lib/ruote/exp/fe_concurrent_iterator.rb +71 -10
  24. data/lib/ruote/exp/fe_cron.rb +3 -10
  25. data/lib/ruote/exp/fe_cursor.rb +14 -4
  26. data/lib/ruote/exp/fe_define.rb +3 -1
  27. data/lib/ruote/exp/fe_echo.rb +1 -1
  28. data/lib/ruote/exp/fe_equals.rb +1 -1
  29. data/lib/ruote/exp/fe_error.rb +1 -1
  30. data/lib/ruote/exp/fe_filter.rb +163 -4
  31. data/lib/ruote/exp/fe_forget.rb +21 -4
  32. data/lib/ruote/exp/fe_given.rb +1 -1
  33. data/lib/ruote/exp/fe_if.rb +1 -1
  34. data/lib/ruote/exp/fe_inc.rb +102 -35
  35. data/lib/ruote/exp/fe_iterator.rb +47 -12
  36. data/lib/ruote/exp/fe_listen.rb +96 -11
  37. data/lib/ruote/exp/fe_lose.rb +31 -4
  38. data/lib/ruote/exp/fe_noop.rb +1 -1
  39. data/lib/ruote/exp/fe_on_error.rb +109 -0
  40. data/lib/ruote/exp/fe_once.rb +10 -19
  41. data/lib/ruote/exp/fe_participant.rb +90 -28
  42. data/lib/ruote/exp/fe_read.rb +69 -0
  43. data/lib/ruote/exp/fe_redo.rb +3 -2
  44. data/lib/ruote/exp/fe_ref.rb +57 -27
  45. data/lib/ruote/exp/fe_registerp.rb +1 -3
  46. data/lib/ruote/exp/fe_reserve.rb +1 -1
  47. data/lib/ruote/exp/fe_restore.rb +6 -6
  48. data/lib/ruote/exp/fe_save.rb +12 -19
  49. data/lib/ruote/exp/fe_sequence.rb +38 -2
  50. data/lib/ruote/exp/fe_set.rb +143 -40
  51. data/lib/ruote/exp/{fe_let.rb → fe_stall.rb} +7 -38
  52. data/lib/ruote/exp/fe_subprocess.rb +8 -2
  53. data/lib/ruote/exp/fe_that.rb +1 -1
  54. data/lib/ruote/exp/fe_undo.rb +40 -4
  55. data/lib/ruote/exp/fe_unregisterp.rb +1 -3
  56. data/lib/ruote/exp/fe_wait.rb +12 -25
  57. data/lib/ruote/exp/{flowexpression.rb → flow_expression.rb} +375 -229
  58. data/lib/ruote/exp/iterator.rb +2 -2
  59. data/lib/ruote/exp/merge.rb +78 -17
  60. data/lib/ruote/exp/ro_attributes.rb +46 -36
  61. data/lib/ruote/exp/ro_filters.rb +34 -8
  62. data/lib/ruote/exp/ro_on_x.rb +431 -0
  63. data/lib/ruote/exp/ro_persist.rb +19 -7
  64. data/lib/ruote/exp/ro_timers.rb +123 -0
  65. data/lib/ruote/exp/ro_variables.rb +90 -29
  66. data/lib/ruote/fei.rb +57 -3
  67. data/lib/ruote/fs.rb +3 -0
  68. data/lib/ruote/id/mnemo_wfid_generator.rb +30 -7
  69. data/lib/ruote/id/wfid_generator.rb +17 -38
  70. data/lib/ruote/log/default_history.rb +23 -9
  71. data/lib/ruote/log/fancy_printing.rb +265 -0
  72. data/lib/ruote/log/storage_history.rb +23 -13
  73. data/lib/ruote/log/wait_logger.rb +224 -17
  74. data/lib/ruote/observer.rb +82 -0
  75. data/lib/ruote/part/block_participant.rb +65 -28
  76. data/lib/ruote/part/code_participant.rb +81 -0
  77. data/lib/ruote/part/engine_participant.rb +7 -2
  78. data/lib/ruote/part/local_participant.rb +221 -21
  79. data/lib/ruote/part/no_op_participant.rb +1 -1
  80. data/lib/ruote/part/null_participant.rb +1 -1
  81. data/lib/ruote/part/participant.rb +50 -0
  82. data/lib/ruote/part/rev_participant.rb +178 -0
  83. data/lib/ruote/part/smtp_participant.rb +2 -2
  84. data/lib/ruote/part/storage_participant.rb +228 -60
  85. data/lib/ruote/part/template.rb +1 -1
  86. data/lib/ruote/participant.rb +2 -0
  87. data/lib/ruote/reader.rb +205 -68
  88. data/lib/ruote/reader/json.rb +49 -0
  89. data/lib/ruote/reader/radial.rb +303 -0
  90. data/lib/ruote/reader/ruby_dsl.rb +44 -9
  91. data/lib/ruote/reader/xml.rb +11 -8
  92. data/lib/ruote/receiver/base.rb +98 -45
  93. data/lib/ruote/storage/base.rb +104 -35
  94. data/lib/ruote/storage/composite_storage.rb +50 -60
  95. data/lib/ruote/storage/fs_storage.rb +25 -34
  96. data/lib/ruote/storage/hash_storage.rb +38 -36
  97. data/lib/ruote/svc/dispatch_pool.rb +104 -35
  98. data/lib/ruote/svc/dollar_sub.rb +10 -8
  99. data/lib/ruote/svc/error_handler.rb +108 -52
  100. data/lib/ruote/svc/expression_map.rb +3 -3
  101. data/lib/ruote/svc/participant_list.rb +160 -55
  102. data/lib/ruote/svc/tracker.rb +31 -31
  103. data/lib/ruote/svc/treechecker.rb +28 -16
  104. data/lib/ruote/tree_dot.rb +1 -1
  105. data/lib/ruote/util/deep.rb +143 -0
  106. data/lib/ruote/util/filter.rb +125 -18
  107. data/lib/ruote/util/hashdot.rb +15 -13
  108. data/lib/ruote/util/look.rb +1 -1
  109. data/lib/ruote/util/lookup.rb +60 -22
  110. data/lib/ruote/util/misc.rb +63 -18
  111. data/lib/ruote/util/mpatch.rb +53 -0
  112. data/lib/ruote/util/ometa.rb +1 -2
  113. data/lib/ruote/util/process_observer.rb +177 -0
  114. data/lib/ruote/util/subprocess.rb +1 -1
  115. data/lib/ruote/util/time.rb +2 -2
  116. data/lib/ruote/util/tree.rb +64 -2
  117. data/lib/ruote/version.rb +3 -2
  118. data/lib/ruote/worker.rb +421 -92
  119. data/lib/ruote/workitem.rb +157 -22
  120. data/ruote.gemspec +15 -9
  121. data/test/bm/ci.rb +0 -2
  122. data/test/bm/ici.rb +0 -2
  123. data/test/bm/load_26c.rb +0 -3
  124. data/test/bm/mega.rb +0 -2
  125. data/test/functional/base.rb +57 -43
  126. data/test/functional/concurrent_base.rb +16 -13
  127. data/test/functional/ct_0_concurrence.rb +7 -11
  128. data/test/functional/ct_1_iterator.rb +9 -11
  129. data/test/functional/ct_2_cancel.rb +28 -17
  130. data/test/functional/eft_0_flow_expression.rb +35 -0
  131. data/test/functional/eft_10_cancel_process.rb +1 -1
  132. data/test/functional/eft_11_wait.rb +13 -13
  133. data/test/functional/eft_12_listen.rb +199 -66
  134. data/test/functional/eft_13_iterator.rb +95 -29
  135. data/test/functional/eft_14_cursor.rb +74 -24
  136. data/test/functional/eft_15_loop.rb +7 -7
  137. data/test/functional/eft_16_if.rb +1 -1
  138. data/test/functional/eft_17_equals.rb +1 -1
  139. data/test/functional/eft_18_concurrent_iterator.rb +156 -68
  140. data/test/functional/eft_19_reserve.rb +15 -15
  141. data/test/functional/eft_1_echo.rb +1 -1
  142. data/test/functional/eft_20_save.rb +51 -9
  143. data/test/functional/eft_21_restore.rb +1 -1
  144. data/test/functional/eft_22_noop.rb +1 -1
  145. data/test/functional/eft_23_apply.rb +1 -1
  146. data/test/functional/eft_24_add_branches.rb +7 -8
  147. data/test/functional/eft_25_command.rb +1 -1
  148. data/test/functional/eft_26_error.rb +11 -11
  149. data/test/functional/eft_27_inc.rb +111 -67
  150. data/test/functional/eft_28_once.rb +16 -16
  151. data/test/functional/eft_29_cron.rb +9 -9
  152. data/test/functional/eft_2_sequence.rb +23 -4
  153. data/test/functional/eft_30_ref.rb +36 -24
  154. data/test/functional/eft_31_registerp.rb +24 -24
  155. data/test/functional/eft_32_lose.rb +46 -20
  156. data/test/functional/eft_34_given.rb +1 -1
  157. data/test/functional/eft_35_filter.rb +161 -7
  158. data/test/functional/eft_36_read.rb +97 -0
  159. data/test/functional/{eft_0_process_definition.rb → eft_37_process_definition.rb} +4 -4
  160. data/test/functional/eft_38_on_error.rb +195 -0
  161. data/test/functional/eft_39_stall.rb +35 -0
  162. data/test/functional/eft_3_participant.rb +77 -22
  163. data/test/functional/eft_40_await.rb +297 -0
  164. data/test/functional/eft_4_set.rb +110 -11
  165. data/test/functional/eft_5_subprocess.rb +27 -5
  166. data/test/functional/eft_6_concurrence.rb +299 -60
  167. data/test/functional/eft_7_forget.rb +24 -22
  168. data/test/functional/eft_8_undo.rb +52 -15
  169. data/test/functional/eft_9_redo.rb +18 -20
  170. data/test/functional/ft_0_worker.rb +122 -13
  171. data/test/functional/ft_10_dollar.rb +77 -16
  172. data/test/functional/ft_11_recursion.rb +9 -9
  173. data/test/functional/ft_12_launchitem.rb +7 -9
  174. data/test/functional/ft_13_variables.rb +125 -22
  175. data/test/functional/ft_14_re_apply.rb +112 -56
  176. data/test/functional/ft_15_timeout.rb +64 -33
  177. data/test/functional/ft_16_participant_params.rb +59 -6
  178. data/test/functional/ft_17_conditional.rb +68 -2
  179. data/test/functional/ft_18_kill.rb +48 -30
  180. data/test/functional/ft_19_participant_code.rb +67 -0
  181. data/test/functional/ft_1_process_status.rb +222 -150
  182. data/test/functional/ft_20_storage_participant.rb +445 -44
  183. data/test/functional/ft_21_forget.rb +21 -26
  184. data/test/functional/ft_22_process_definitions.rb +8 -6
  185. data/test/functional/ft_23_load_defs.rb +29 -5
  186. data/test/functional/ft_24_block_participant.rb +199 -20
  187. data/test/functional/ft_25_receiver.rb +98 -46
  188. data/test/functional/ft_26_participant_rtimeout.rb +34 -26
  189. data/test/functional/ft_27_var_indirection.rb +40 -5
  190. data/test/functional/ft_28_null_noop_participants.rb +5 -5
  191. data/test/functional/ft_29_part_template.rb +2 -2
  192. data/test/functional/ft_2_errors.rb +106 -74
  193. data/test/functional/ft_30_smtp_participant.rb +7 -7
  194. data/test/functional/ft_31_part_blocking.rb +11 -11
  195. data/test/functional/ft_32_scope.rb +50 -0
  196. data/test/functional/ft_33_participant_subprocess_priority.rb +3 -3
  197. data/test/functional/ft_34_cursor_rewind.rb +14 -14
  198. data/test/functional/ft_35_add_service.rb +67 -9
  199. data/test/functional/ft_36_storage_history.rb +92 -24
  200. data/test/functional/ft_37_default_history.rb +35 -23
  201. data/test/functional/ft_38_participant_more.rb +189 -32
  202. data/test/functional/ft_39_wait_for.rb +25 -25
  203. data/test/functional/ft_3_participant_registration.rb +235 -107
  204. data/test/functional/ft_40_wait_logger.rb +105 -18
  205. data/test/functional/ft_41_participants.rb +13 -12
  206. data/test/functional/ft_42_storage_copy.rb +12 -12
  207. data/test/functional/ft_43_participant_on_reply.rb +85 -11
  208. data/test/functional/ft_44_var_participant.rb +5 -5
  209. data/test/functional/ft_45_participant_accept.rb +3 -3
  210. data/test/functional/ft_46_launch_single.rb +17 -17
  211. data/test/functional/ft_47_wfids.rb +41 -0
  212. data/test/functional/ft_48_lose.rb +19 -25
  213. data/test/functional/ft_49_engine_on_error.rb +54 -70
  214. data/test/functional/ft_4_cancel.rb +84 -26
  215. data/test/functional/ft_50_engine_config.rb +4 -4
  216. data/test/functional/ft_51_misc.rb +12 -12
  217. data/test/functional/ft_52_case.rb +17 -17
  218. data/test/functional/ft_53_engine_on_terminate.rb +18 -21
  219. data/test/functional/ft_54_patterns.rb +18 -16
  220. data/test/functional/ft_55_engine_participant.rb +55 -55
  221. data/test/functional/ft_56_filter_attribute.rb +90 -52
  222. data/test/functional/ft_57_rev_participant.rb +252 -0
  223. data/test/functional/ft_58_workitem.rb +150 -0
  224. data/test/functional/ft_59_pause.rb +329 -0
  225. data/test/functional/ft_5_on_error.rb +430 -77
  226. data/test/functional/ft_60_code_participant.rb +65 -0
  227. data/test/functional/ft_61_trailing_fields.rb +34 -0
  228. data/test/functional/ft_62_exp_name_and_dollar_substitution.rb +35 -0
  229. data/test/functional/ft_63_participants_221.rb +458 -0
  230. data/test/functional/ft_64_stash.rb +41 -0
  231. data/test/functional/ft_65_timers.rb +313 -0
  232. data/test/functional/ft_66_flank.rb +133 -0
  233. data/test/functional/ft_67_radial_misc.rb +34 -0
  234. data/test/functional/ft_68_reput.rb +72 -0
  235. data/test/functional/ft_69_worker_info.rb +56 -0
  236. data/test/functional/ft_6_on_cancel.rb +189 -36
  237. data/test/functional/ft_70_take_and_discard_attributes.rb +94 -0
  238. data/test/functional/ft_71_retries.rb +144 -0
  239. data/test/functional/ft_72_on_terminate.rb +60 -0
  240. data/test/functional/ft_73_raise_msg.rb +107 -0
  241. data/test/functional/ft_74_respark.rb +106 -0
  242. data/test/functional/ft_75_context.rb +66 -0
  243. data/test/functional/ft_76_observer.rb +53 -0
  244. data/test/functional/ft_77_process_observer.rb +157 -0
  245. data/test/functional/ft_78_part_participant.rb +37 -0
  246. data/test/functional/ft_7_tags.rb +238 -50
  247. data/test/functional/ft_8_participant_consumption.rb +27 -21
  248. data/test/functional/ft_9_subprocesses.rb +48 -18
  249. data/test/functional/restart_base.rb +4 -6
  250. data/test/functional/rt_0_wait.rb +10 -10
  251. data/test/functional/rt_1_listen.rb +6 -6
  252. data/test/functional/rt_2_errors.rb +12 -12
  253. data/test/functional/rt_3_once.rb +17 -12
  254. data/test/functional/rt_4_cron.rb +17 -17
  255. data/test/functional/rt_5_timeout.rb +13 -13
  256. data/test/functional/signals.rb +103 -0
  257. data/test/functional/storage.rb +730 -0
  258. data/test/functional/storage_helper.rb +48 -35
  259. data/test/functional/test.rb +6 -2
  260. data/test/misc/idle.rb +21 -0
  261. data/test/misc/light.rb +29 -0
  262. data/test/path_helper.rb +1 -1
  263. data/test/test.rb +2 -5
  264. data/test/test_helper.rb +13 -0
  265. data/test/unit/test.rb +1 -4
  266. data/test/unit/ut_0_ruby_reader.rb +25 -9
  267. data/test/unit/ut_10_participants.rb +47 -0
  268. data/test/unit/ut_11_lookup.rb +59 -2
  269. data/test/unit/ut_12_wait_logger.rb +123 -0
  270. data/test/unit/ut_14_is_uri.rb +1 -1
  271. data/test/unit/ut_15_util.rb +1 -1
  272. data/test/unit/ut_16_reader.rb +136 -14
  273. data/test/unit/ut_17_merge.rb +155 -0
  274. data/test/unit/ut_19_part_template.rb +1 -1
  275. data/test/unit/ut_1_fei.rb +11 -2
  276. data/test/unit/ut_20_composite_storage.rb +27 -1
  277. data/test/unit/{ut_21_participant_list.rb → ut_21_svc_participant_list.rb} +2 -3
  278. data/test/unit/ut_22_filter.rb +231 -10
  279. data/test/unit/ut_23_svc_tracker.rb +48 -0
  280. data/test/unit/ut_24_radial_reader.rb +458 -0
  281. data/test/unit/ut_25_process_status.rb +143 -0
  282. data/test/unit/ut_26_deep.rb +131 -0
  283. data/test/unit/ut_2_dashboard.rb +114 -0
  284. data/test/unit/ut_3_worker.rb +54 -0
  285. data/test/unit/ut_4_expmap.rb +1 -1
  286. data/test/unit/ut_5_tree.rb +23 -23
  287. data/test/unit/ut_6_condition.rb +71 -29
  288. data/test/unit/ut_7_workitem.rb +18 -4
  289. data/test/unit/ut_8_tree_to_dot.rb +1 -1
  290. data/test/unit/ut_9_xml_reader.rb +1 -1
  291. metadata +142 -63
  292. data/jruby_issue.txt +0 -32
  293. data/lib/ruote/engine/process_status.rb +0 -403
  294. data/lib/ruote/log/pretty.rb +0 -165
  295. data/lib/ruote/log/test_logger.rb +0 -204
  296. data/lib/ruote/util/serializer.rb +0 -103
  297. data/phil.txt +0 -14
  298. data/test/functional/eft_33_let.rb +0 -31
  299. data/test/functional/ft_19_alias.rb +0 -33
  300. data/test/functional/ft_47_wfid_generator.rb +0 -54
  301. data/test/unit/storage.rb +0 -403
  302. data/test/unit/storages.rb +0 -37
  303. data/test/unit/ut_13_serializer.rb +0 -65
  304. data/test/unit/ut_18_engine.rb +0 -47
  305. data/test/unit/ut_3_wait_logger.rb +0 -39
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
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
@@ -41,8 +41,11 @@ module Ruote
41
41
  #
42
42
  # process_history = engine.history.by_wfid(wfid0)
43
43
  #
44
- # Note that, by default, the history is an in-memory history (and it is
45
- # useless when there are multiple workers).
44
+ #
45
+ # == final note
46
+ #
47
+ # By default, the history is an in-memory history (see Ruote::DefaultHistory)
48
+ # (and it is worthless when there are multiple workers).
46
49
  #
47
50
  class StorageHistory
48
51
 
@@ -53,13 +56,7 @@ module Ruote
53
56
  @context = context
54
57
  @options = options
55
58
 
56
- if @context.worker
57
-
58
- # only care about logging if there is a worker present
59
-
60
- @context.storage.add_type('history')
61
- @context.worker.subscribe(:all, self)
62
- end
59
+ @context.storage.add_type('history')
63
60
  end
64
61
 
65
62
  # Returns all the wfids for which there are history items (msgs) stored.
@@ -126,10 +123,12 @@ module Ruote
126
123
  @context.storage.purge_type!('history')
127
124
  end
128
125
 
129
- # This is the method called by the workqueue. Incoming engine events
130
- # are 'processed' here.
126
+ # This method is called by the worker via the context. Successfully
127
+ # processed msgs are passed here.
131
128
  #
132
- def notify(msg)
129
+ def on_msg(msg)
130
+
131
+ return unless accept?(msg)
133
132
 
134
133
  msg = msg.dup
135
134
  # a shallow copy is sufficient
@@ -151,6 +150,17 @@ module Ruote
151
150
 
152
151
  @context.storage.put(msg)
153
152
  end
153
+
154
+ protected
155
+
156
+ # This default implementation lets all the messages in.
157
+ #
158
+ # Feel free to override this method in a subclass.
159
+ #
160
+ def accept?(msg)
161
+
162
+ true
163
+ end
154
164
  end
155
165
  end
156
166
 
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
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
@@ -22,45 +22,252 @@
22
22
  # Made in Japan.
23
23
  #++
24
24
 
25
- require 'ruote/log/test_logger'
26
-
27
25
 
28
26
  module Ruote
29
27
 
28
+ # The error raised by WaitLogger#wait_for upon a timeout.
29
+ #
30
+ class LoggerTimeout < StandardError
31
+
32
+ def initialize(interests, timeout)
33
+
34
+ super("waited for #{interests.inspect}, timed out after #{timeout}s")
35
+ end
36
+ end
37
+
38
+ #
39
+ # The logic behind Ruote::Dashboard#wait_for is implemented here.
40
+ #
41
+ # This logger keeps track of the last 147 events. This number can
42
+ # be tweaked via the 'wait_logger_max' storage option
43
+ # (http://ruote.rubyforge.org/configuration.html)
44
+ #
45
+ # One doesn't play directly with this class. It's available only via
46
+ # the Ruote::Dashboard#wait_for and Ruote::Dashboard#noisy=
30
47
  #
31
- # A helper logger for quickstart examples.
48
+ # To access the log of processed msgs, look at history services, not
49
+ # at this wait_logger.
32
50
  #
33
- # Keeps a maximum of 147 messages.
51
+ # === options (storage initialization options)
34
52
  #
35
- class WaitLogger < TestLogger
53
+ # wait_logger_max(Integer)::
54
+ # defaults to 147, max number of recent records to keep track of
55
+ # wait_logger_timeout(Integer)::
56
+ # defaults to 60 (seconds), #wait_for times out after how many seconds?
57
+ #
58
+ class WaitLogger
59
+
60
+ require 'ruote/log/fancy_printing'
61
+
62
+ attr_reader :seen
63
+ attr_reader :log
36
64
 
65
+ # When set to true, this logger will spit out the ruote activity
66
+ # happening in this Ruby's runtime ruote worker (if any) to $stdout.
67
+ #
37
68
  attr_accessor :noisy
38
69
 
70
+ # The timeout for #wait_for. Defaults to 60 (seconds). When set to
71
+ # number inferior or equal to zero, no timeout will be enforced.
72
+ #
73
+ attr_accessor :timeout
74
+
39
75
  def initialize(context)
40
76
 
41
77
  @context = context
42
- @color = 33
43
78
 
44
- @context.worker.subscribe(:all, self) if @context.worker
79
+ @seen = []
80
+ @log = []
81
+ @waiting = []
45
82
 
46
- @noisy = false
47
83
  @count = -1
84
+ @color = 33
85
+ @noisy = false
48
86
 
49
- @seen = []
50
- @waiting = []
87
+ @log_max = context['wait_logger_max'] || 147
88
+ @timeout = context['wait_logger_timeout'] || 60 # in seconds
89
+
90
+ @check_mutex = Mutex.new
51
91
  end
52
92
 
53
- def notify(msg)
93
+ # The context will call this method for each msg sucessfully processed
94
+ # by the worker.
95
+ #
96
+ def on_msg(msg)
54
97
 
55
- puts(pretty_print(msg)) if @noisy
98
+ puts(fancy_print(msg, @noisy)) if @noisy
56
99
 
57
- #return if @waiting.size < 1
58
- #check_msg(msg)
100
+ return if msg['action'] == 'noop'
59
101
 
60
102
  @seen << msg
61
- @seen.shift if @seen.size > 147
103
+ @log << msg
104
+
105
+ while @log.size > @log_max; @log.shift; end
106
+ while @seen.size > @log_max; @seen.shift; end
107
+ end
108
+
109
+ # Returns an array of the latest msgs, but fancy-printed. The oldest
110
+ # first.
111
+ #
112
+ def fancy_log
113
+
114
+ @log.collect { |msg| fancy_print(msg) }
115
+ end
116
+
117
+ # Debug only : dumps all the seen events to $stdout
118
+ #
119
+ def dump
120
+
121
+ @seen.collect { |msg| fancy_print(msg) }.join("\n")
122
+ end
123
+
124
+ # Blocks until one or more interests are satisfied.
125
+ #
126
+ # interests must be an array of interests. Please refer to
127
+ # Dashboard#wait_for documentation for allowed values of each interest.
128
+ #
129
+ # If multiple interests are given, wait_for blocks until
130
+ # all of the interests are satisfied.
131
+ #
132
+ # wait_for may only be used by one thread at a time. If one
133
+ # thread calls wait_for and later another thread calls wait_for
134
+ # while the first thread is waiting, the first thread's
135
+ # interests are lost and the first thread will never wake up.
136
+ #
137
+ def wait_for(interests, opts={})
138
+
139
+ @waiting << [ Thread.current, interests ]
140
+
141
+ Thread.current['__result__'] = nil
142
+ start = Time.now
143
+
144
+ to = opts[:timeout] || @timeout
145
+ to = nil if to.nil? || to <= 0
146
+
147
+ loop do
148
+
149
+ raise(
150
+ Ruote::LoggerTimeout.new(interests, to)
151
+ ) if to && (Time.now - start) > to
152
+
153
+ @check_mutex.synchronize { check_waiting }
154
+
155
+ break if Thread.current['__result__']
156
+
157
+ sleep 0.007
158
+ end
159
+
160
+ Thread.current['__result__']
161
+ end
162
+
163
+ def color=(c)
164
+
165
+ @color = c
166
+ end
167
+
168
+ def self.fp(msg)
169
+
170
+ @logger ||= TestLogger.new(nil)
171
+ puts @logger.send(:fancy_print, msg)
172
+ end
173
+
174
+ protected
175
+
176
+ def check_waiting
177
+
178
+ while @waiting.any? and msg = @seen.shift
179
+
180
+ @waiting.delete_if do |thread, interests|
181
+ thread['__result__'] = msg if matches(interests, msg)
182
+ (interests.size < 1)
183
+ end
184
+ end
185
+ end
186
+
187
+ FINAL_ACTIONS = %w[
188
+ terminated ceased error_intercepted
189
+ ]
190
+ ACTIONS = FINAL_ACTIONS + %w[
191
+ launch apply reply
192
+ fail
193
+ dispatch dispatched receive
194
+ cancel dispatch_cancel kill
195
+ pause resume dispatch_pause dispatch_resume
196
+ regenerate
197
+ pause_process resume_process cancel_process kill_process
198
+ reput noop raise
199
+ respark
200
+ ]
201
+
202
+ # Checks whether message msg matches any of interests being waited for.
203
+ #
204
+ # Some interests look for actions on particular workflows (e.g.,
205
+ # waiting for some workflow to finish). Other interests are not
206
+ # attached to any particular workflow (e.g., :inactive waits until
207
+ # the engine finishes processing all active and pending workflows)
208
+ # but are still satisfied when actions happen on workflows (e.g.,
209
+ # the last workflow being run finishes).
210
+ #
211
+ # Returns true if all interests being waited for have been satisfied,
212
+ # false otherwise.
213
+ #
214
+ def matches(interests, msg)
215
+
216
+ action = msg['action']
217
+
218
+ interests.each do |interest|
219
+
220
+ satisfied = case interest
221
+
222
+ when :or_error
223
+ #
224
+ # let's force an immediate reply
225
+
226
+ interests.clear if action == 'error_intercepted'
227
+
228
+ when :inactive
229
+
230
+ (FINAL_ACTIONS.include?(action) && @context.worker.inactive?)
231
+
232
+ when :empty
233
+
234
+ (action == 'terminated' && @context.storage.empty?('expressions'))
235
+
236
+ when Symbol
237
+
238
+ (action == 'dispatch' && msg['participant_name'] == interest.to_s)
239
+
240
+ when Fixnum
241
+
242
+ interests.delete(interest)
243
+
244
+ if (interest > 1)
245
+ interests << (interest - 1)
246
+ false
247
+ else
248
+ true
249
+ end
250
+
251
+ when Hash
252
+
253
+ interest.all? { |k, v|
254
+ k = 'tree.0' if k == 'exp_name'
255
+ Ruote.lookup(msg, k) == v
256
+ }
257
+
258
+ when /^[a-z_]+$/
259
+
260
+ (action == interest)
261
+
262
+ else # wfid
263
+
264
+ (FINAL_ACTIONS.include?(action) && msg['wfid'] == interest)
265
+ end
266
+
267
+ interests.delete(interest) if satisfied
268
+ end
62
269
 
63
- check_waiting
270
+ (interests.size < 1)
64
271
  end
65
272
  end
66
273
  end
@@ -0,0 +1,82 @@
1
+ #--
2
+ # Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+ # Made in Japan.
23
+ #++
24
+
25
+
26
+ module Ruote
27
+
28
+ #
29
+ # An abstract class for observing the activity of a ruote engine.
30
+ #
31
+ # Subclass it and add it as a service to observe certain events.
32
+ #
33
+ # require 'ruote/observer'
34
+ #
35
+ # class MyLaunchObserver < Ruote::Observer
36
+ #
37
+ # def on_msg_launch(msg)
38
+ # puts "just launched process instance #{msg['wfid']}"
39
+ # end
40
+ # end
41
+ #
42
+ # dashboard.add_service('launch_observer', MyLaunchObserver)
43
+ #
44
+ # # ...
45
+ #
46
+ # Simply add a "on_msg_<msg_name>" method for it to intercept the
47
+ # given messages.
48
+ #
49
+ # See Ruote::ProcessObserver for a base class with precisely defined
50
+ # methods with helpful arguments if you don't want to investigate
51
+ # "msgs" too much.
52
+ #
53
+ class Observer
54
+
55
+ def initialize(context)
56
+
57
+ @context = context
58
+ end
59
+
60
+ def on_pre_msg(msg)
61
+
62
+ route('pre', msg)
63
+ end
64
+
65
+ def on_msg(msg)
66
+
67
+ route(nil, msg)
68
+ end
69
+
70
+ protected
71
+
72
+ def route(time, msg)
73
+
74
+ target = [ 'on', time, 'msg', msg['action'] ].compact.join('_')
75
+
76
+ return unless self.respond_to?(target)
77
+
78
+ send(target, msg)
79
+ end
80
+ end
81
+ end
82
+
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
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
@@ -22,8 +22,6 @@
22
22
  # Made in Japan.
23
23
  #++
24
24
 
25
- require 'ruote/part/local_participant'
26
-
27
25
 
28
26
  module Ruote
29
27
 
@@ -48,19 +46,20 @@ module Ruote
48
46
  # == do_not_thread
49
47
  #
50
48
  # By default, this participant (like most other participants) is executed
51
- # in its own thread (in a Ruby runtime where EventMachine is running,
52
- # EM.next_tick is used instead of a new thread).
49
+ # in its own thread.
53
50
  #
54
- # You can change that behaviour (beware block thats monopolises the whole
55
- # engine !) by doing
56
51
  #
57
- # alpha = engine.register_participant :alpha do |workitem|
58
- # workitem.fields['time'] = Time.now
59
- # end
52
+ # == context
60
53
  #
61
- # alpha.do_not_thread = true
54
+ # As it includes Ruote::LocalParticipant, the block partitcipant has
55
+ # access to:
62
56
  #
63
- # (you could also override do_not_thread, the method ...)
57
+ # * #context: the ruote context
58
+ # * #workitem: the current workitem (usually passed as arg to the block)
59
+ # * #fei: the current flow expression id
60
+ # * #fexp: the current flow expression
61
+ # * #flavour: only used in #on_cancel (nil or 'kill')
62
+ # * #lookup_variable(key): looks up a variable...
64
63
  #
65
64
  class BlockParticipant
66
65
 
@@ -73,26 +72,14 @@ module Ruote
73
72
  @opts = opts
74
73
  end
75
74
 
76
- def do_not_thread
77
-
78
- @opts['do_not_thread']
79
- end
80
-
81
- def consume(workitem)
75
+ def on_workitem
82
76
 
83
- block = @opts['block']
84
-
85
- @context.treechecker.block_check(block)
86
- # raises in case of 'security' violation
87
-
88
- #block = eval(block, @context.send(:binding))
89
- # doesn't work with ruby 1.9.2-p136
90
- block = eval(block, @context.instance_eval { binding })
91
- # works OK with ruby 1.8.7-249 and 1.9.2-p136
77
+ block = get_block('on_workitem', 'block')
92
78
 
93
79
  r = if block.arity == 1
94
80
 
95
81
  block.call(workitem)
82
+
96
83
  else
97
84
 
98
85
  block.call(
@@ -108,7 +95,57 @@ module Ruote
108
95
 
109
96
  def cancel(fei, flavour)
110
97
 
111
- # do nothing
98
+ if block = get_block('on_cancel')
99
+ block.call(fei, flavour)
100
+ end
101
+ end
102
+
103
+ def on_reply(workitem)
104
+
105
+ if block = get_block('on_reply')
106
+ block.call(workitem)
107
+ end
108
+ end
109
+
110
+ def accept?(workitem)
111
+
112
+ if block = get_block('accept?')
113
+ block.call(workitem)
114
+ else
115
+ true
116
+ end
117
+ end
118
+
119
+ def do_not_thread(workitem)
120
+
121
+ dnt = @opts['do_not_thread']
122
+
123
+ return dnt unless dnt.is_a?(String)
124
+
125
+ block = get_block('do_not_thread')
126
+
127
+ block.call(workitem)
128
+ end
129
+
130
+ protected
131
+
132
+ def get_block(*keys)
133
+
134
+ key = keys.find { |k| @opts[k] }
135
+
136
+ return nil unless key
137
+
138
+ block = @opts[key]
139
+
140
+ @context.treechecker.block_check(block)
141
+ # raises in case of 'security' violation
142
+
143
+ #eval(block, @context.send(:binding))
144
+ # doesn't work with ruby 1.9.2-p136
145
+ #eval(block, @context.instance_eval { binding })
146
+ # works OK with ruby 1.8.7-249 and 1.9.2-p136
147
+ eval(block, self.instance_eval { binding })
148
+ # works OK with ruby 1.8.7-249 and 1.9.2-p136
112
149
  end
113
150
  end
114
151
  end