ruote 2.1.9 → 2.1.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/CHANGELOG.txt +32 -0
  2. data/CREDITS.txt +3 -0
  3. data/Rakefile +4 -4
  4. data/TODO.txt +55 -11
  5. data/examples/barley.rb +2 -1
  6. data/examples/flickr_report.rb +5 -6
  7. data/examples/web_first_page.rb +11 -0
  8. data/lib/ruote/context.rb +36 -13
  9. data/lib/ruote/engine.rb +88 -56
  10. data/lib/ruote/engine/process_error.rb +13 -0
  11. data/lib/ruote/engine/process_status.rb +33 -1
  12. data/lib/ruote/error_handler.rb +122 -0
  13. data/lib/ruote/evt/tracker.rb +27 -10
  14. data/lib/ruote/exp/fe_apply.rb +69 -0
  15. data/lib/ruote/exp/fe_participant.rb +33 -5
  16. data/lib/ruote/exp/flowexpression.rb +37 -5
  17. data/lib/ruote/exp/ro_persist.rb +8 -4
  18. data/lib/ruote/exp/ro_variables.rb +2 -2
  19. data/lib/ruote/fei.rb +59 -7
  20. data/lib/ruote/log/storage_history.rb +2 -0
  21. data/lib/ruote/log/test_logger.rb +28 -19
  22. data/lib/ruote/log/wait_logger.rb +4 -2
  23. data/lib/ruote/parser.rb +2 -1
  24. data/lib/ruote/part/dispatch_pool.rb +10 -10
  25. data/lib/ruote/part/engine_participant.rb +2 -2
  26. data/lib/ruote/part/local_participant.rb +99 -7
  27. data/lib/ruote/part/participant_list.rb +18 -7
  28. data/lib/ruote/part/storage_participant.rb +9 -6
  29. data/lib/ruote/receiver/base.rb +109 -10
  30. data/lib/ruote/storage/base.rb +118 -41
  31. data/lib/ruote/storage/fs_storage.rb +1 -0
  32. data/lib/ruote/storage/hash_storage.rb +2 -1
  33. data/lib/ruote/util/lookup.rb +22 -2
  34. data/lib/ruote/util/misc.rb +5 -5
  35. data/lib/ruote/version.rb +1 -1
  36. data/lib/ruote/worker.rb +50 -63
  37. data/lib/ruote/workitem.rb +64 -0
  38. data/ruote.gemspec +17 -12
  39. data/test/functional/base.rb +3 -1
  40. data/test/functional/concurrent_base.rb +35 -29
  41. data/test/functional/crunner.sh +19 -0
  42. data/test/functional/ct_0_concurrence.rb +17 -30
  43. data/test/functional/ct_1_iterator.rb +20 -17
  44. data/test/functional/ct_2_cancel.rb +32 -25
  45. data/test/functional/eft_12_listen.rb +2 -1
  46. data/test/functional/eft_23_apply.rb +23 -0
  47. data/test/functional/eft_3_participant.rb +27 -0
  48. data/test/functional/ft_11_recursion.rb +1 -1
  49. data/test/functional/ft_13_variables.rb +22 -0
  50. data/test/functional/ft_14_re_apply.rb +3 -0
  51. data/test/functional/ft_15_timeout.rb +1 -0
  52. data/test/functional/ft_20_storage_participant.rb +20 -2
  53. data/test/functional/ft_21_forget.rb +30 -0
  54. data/test/functional/ft_22_process_definitions.rb +2 -1
  55. data/test/functional/ft_24_block_participants.rb +1 -1
  56. data/test/functional/ft_25_receiver.rb +83 -1
  57. data/test/functional/ft_26_participant_timeout.rb +1 -1
  58. data/test/functional/ft_2_errors.rb +2 -5
  59. data/test/functional/ft_30_smtp_participant.rb +47 -45
  60. data/test/functional/ft_36_storage_history.rb +4 -4
  61. data/test/functional/ft_37_engine_participant.rb +14 -10
  62. data/test/functional/ft_38_participant_more.rb +178 -0
  63. data/test/functional/ft_39_wait_for.rb +100 -0
  64. data/test/functional/ft_40_participant_on_reply.rb +87 -0
  65. data/test/functional/ft_41_participants.rb +65 -0
  66. data/test/functional/ft_42_storage_copy.rb +67 -0
  67. data/test/functional/ft_5_on_error.rb +103 -0
  68. data/test/functional/ft_9_subprocesses.rb +2 -1
  69. data/test/functional/storage_helper.rb +5 -1
  70. data/test/functional/test.rb +4 -1
  71. data/test/functional/vertical.rb +46 -0
  72. data/test/unit/storage.rb +17 -1
  73. data/test/unit/storages.rb +27 -7
  74. data/test/unit/ut_11_lookup.rb +36 -0
  75. data/test/unit/ut_16_parser.rb +43 -0
  76. data/test/unit/ut_1_fei.rb +28 -1
  77. data/test/unit/ut_7_workitem.rb +23 -0
  78. metadata +67 -105
  79. data/lib/ruote/log/fs_history.rb +0 -182
  80. data/test/functional/ft_32_fs_history.rb +0 -188
  81. data/test/mpc_test.rb +0 -29
@@ -38,6 +38,7 @@ require 'rufus/cloche'
38
38
 
39
39
  module Ruote
40
40
 
41
+ #
41
42
  # A basic FS-bound ruote storage. Leverages rufus-cloche
42
43
  # (http://github.com/jmettraux/rufus-cloche).
43
44
  #
@@ -57,7 +57,8 @@ module Ruote
57
57
 
58
58
  pre = get(doc['type'], doc['_id'])
59
59
 
60
- if pre && ( ! opts[:update_rev]) && pre['_rev'] != doc['_rev']
60
+ #if pre && ( ! opts[:update_rev]) && pre['_rev'] != doc['_rev']
61
+ if pre && pre['_rev'] != doc['_rev']
61
62
  return pre
62
63
  end
63
64
 
@@ -34,8 +34,9 @@ module Ruote
34
34
  key, rest = pop_key(key)
35
35
  value = flookup(collection, key)
36
36
 
37
+ return [ key, collection ] if container_lookup && rest.size == 0
37
38
  return [ rest.first, value ] if container_lookup && rest.size == 1
38
- return value if rest.empty?
39
+ return value if rest.size == 0
39
40
  return nil if value == nil
40
41
 
41
42
  lookup(value, rest)
@@ -59,7 +60,26 @@ module Ruote
59
60
  end
60
61
  end
61
62
 
62
- protected
63
+ # h = { 'customer' => { 'name' => 'alpha', 'rank' => '1st' } }
64
+ # r = Ruote.unset(h, 'customer.rank')
65
+ #
66
+ # h # => { 'customer' => { 'name' => 'alpha' } }
67
+ # r # => '1st'
68
+ #
69
+ def Ruote.unset (collection, key)
70
+
71
+ k, c = lookup(collection, key, true)
72
+
73
+ return collection.delete(key) unless c
74
+
75
+ if c.is_a?(Array)
76
+ c.delete_at(Integer(k)) rescue nil
77
+ else
78
+ c.delete(k)
79
+ end
80
+ end
81
+
82
+ protected # well...
63
83
 
64
84
  def Ruote.pop_key (key)
65
85
 
@@ -58,11 +58,11 @@ module Ruote
58
58
  rescue TypeError => te
59
59
  end
60
60
 
61
- if object.is_a?(REXML::Element)
62
- d = REXML::Document.new object.to_s
63
- return d if object.kind_of?(REXML::Document)
64
- return d.root
65
- end
61
+ #if object.is_a?(REXML::Element)
62
+ # d = REXML::Document.new object.to_s
63
+ # return d if object.kind_of?(REXML::Document)
64
+ # return d.root
65
+ #end
66
66
  # avoiding "TypeError: singleton can't be dumped"
67
67
 
68
68
  o = object.class.allocate
@@ -23,6 +23,6 @@
23
23
  #++
24
24
 
25
25
  module Ruote
26
- VERSION = '2.1.9'
26
+ VERSION = '2.1.10'
27
27
  end
28
28
 
@@ -27,9 +27,14 @@ require 'ruote/fei'
27
27
 
28
28
  module Ruote
29
29
 
30
+ #
31
+ # Workers fetch 'msgs' and 'schedules' from the storage and process them.
32
+ #
33
+ # Read more at http://ruote.rubyforge.org/configuration.html
34
+ #
30
35
  class Worker
31
36
 
32
- EXP_ACTIONS = %w[ reply cancel fail receive ]
37
+ EXP_ACTIONS = %w[ reply cancel fail receive dispatched ]
33
38
  # 'apply' is comprised in 'launch'
34
39
  # 'receive' is a ParticipantExpression alias for 'reply'
35
40
 
@@ -43,10 +48,12 @@ module Ruote
43
48
 
44
49
  def initialize (storage)
45
50
 
46
- @storage = storage
47
-
48
51
  @subscribers = []
49
- @context = Ruote::Context.new(@storage, self)
52
+ # must be ready before the storage is created
53
+ # services like Logger to subscribe to the worker
54
+
55
+ @storage = storage
56
+ @context = Ruote::Context.new(storage, self)
50
57
 
51
58
  @last_time = Time.at(0.0).utc # 1970...
52
59
 
@@ -54,7 +61,7 @@ module Ruote
54
61
  @run_thread = nil
55
62
 
56
63
  @msgs = []
57
- @sleep_time = 0.001
64
+ @sleep_time = 0.000
58
65
  end
59
66
 
60
67
  def run
@@ -66,7 +73,7 @@ module Ruote
66
73
 
67
74
  def run_in_thread
68
75
 
69
- #Thread.abort_on_exception = true
76
+ Thread.abort_on_exception = true
70
77
  # TODO : remove me at some point
71
78
 
72
79
  @running = true
@@ -82,62 +89,40 @@ module Ruote
82
89
  def shutdown
83
90
 
84
91
  @running = false
85
- @run_thread.join if @run_thread
92
+
93
+ return unless @run_thread
94
+
95
+ begin
96
+ @run_thread.join
97
+ rescue Exception => e
98
+ end
86
99
  end
87
100
 
88
- # This method is public, since it's used by the DispatchPool when
89
- # reporting an error that occurred in the dispatch/consume thread of
90
- # a participant.
101
+ # Returns true if the engine system is inactive, ie if all the process
102
+ # instances are terminated or are stuck in an error.
91
103
  #
92
- def handle_exception (msg, fexp, ex)
93
-
94
- wfid = msg['wfid'] || (msg['fei']['wfid'] rescue nil)
95
- fei = msg['fei'] || (fexp.h.fei rescue nil)
96
-
97
- # debug only
98
-
99
- if ARGV.include?('-d')
100
-
101
- puts "\n== worker intercepted error =="
102
- puts
103
- p ex
104
- ex.backtrace[0, 10].each { |l| puts l }
105
- puts "..."
106
- puts
107
- puts "-- msg --"
108
- msg.keys.sort.each { |k|
109
- puts " #{k.inspect} =>\n#{msg[k].inspect}"
110
- }
111
- puts "-- . --"
112
- puts
113
- end
104
+ # NOTE : for now, if a branch of a process is in errors while another is
105
+ # still running, this methods will still consider the process instance
106
+ # as inactive (and it will return true if all the processes are considered
107
+ # inactive).
108
+ #
109
+ def inactive?
114
110
 
115
- # on_error ?
111
+ # the cheaper tests first
116
112
 
117
- if not(fexp) && fei
118
- fexp = Ruote::Exp::FlowExpression.fetch(@context, fei)
119
- end
113
+ return false if @msgs.size > 0
114
+ return false unless @context.storage.empty?('schedules')
115
+ return false unless @context.storage.empty?('msgs')
120
116
 
121
- return if fexp && fexp.handle_on_error
117
+ wfids = @context.storage.get_many('expressions').collect { |exp|
118
+ exp['fei']['wfid']
119
+ }.sort.uniq
122
120
 
123
- # emit 'msg'
121
+ error_wfids = @context.storage.get_many('errors').collect { |err|
122
+ err['fei']['wfid']
123
+ }.sort.uniq
124
124
 
125
- @storage.put_msg(
126
- 'error_intercepted',
127
- 'message' => ex.inspect,
128
- 'wfid' => wfid,
129
- 'msg' => msg)
130
-
131
- # fill error in the error journal
132
-
133
- @storage.put(
134
- 'type' => 'errors',
135
- '_id' => "err_#{Ruote.to_storage_id(fei)}",
136
- 'message' => ex.inspect,
137
- 'trace' => ex.backtrace.join("\n"),
138
- 'fei' => fei,
139
- 'msg' => msg
140
- ) if fei
125
+ (wfids - error_wfids == [])
141
126
  end
142
127
 
143
128
  protected
@@ -186,14 +171,14 @@ module Ruote
186
171
  break if Time.now.utc - @last_time >= 0.8
187
172
  end
188
173
 
189
- #puts processed.to_s
174
+ #p processed
190
175
 
191
176
  if processed == 0
192
177
  @sleep_time += 0.001
193
178
  @sleep_time = 0.499 if @sleep_time > 0.499
194
179
  sleep(@sleep_time)
195
180
  else
196
- @sleep_time = 0.001
181
+ @sleep_time = 0.000
197
182
  end
198
183
  end
199
184
 
@@ -201,7 +186,7 @@ module Ruote
201
186
 
202
187
  msg = Ruote.fulldup(schedule['msg'])
203
188
 
204
- return false unless @storage.delete(schedule).nil?
189
+ return false unless @storage.reserve(schedule)
205
190
 
206
191
  @storage.put_msg(msg.delete('action'), msg)
207
192
 
@@ -212,7 +197,7 @@ module Ruote
212
197
 
213
198
  return false if cannot_handle(msg)
214
199
 
215
- return false unless @storage.delete(msg).nil?
200
+ return false unless @storage.reserve(msg)
216
201
 
217
202
  begin
218
203
 
@@ -242,9 +227,9 @@ module Ruote
242
227
 
243
228
  notify(msg)
244
229
 
245
- rescue Exception => ex
230
+ rescue Exception => exception
246
231
 
247
- handle_exception(msg, nil, ex)
232
+ @context.error_handler.msg_handle(msg, exception)
248
233
  end
249
234
 
250
235
  true
@@ -260,6 +245,10 @@ module Ruote
260
245
  end
261
246
  end
262
247
 
248
+ # Should always return false. Except when the message is a 'dispatch'
249
+ # and it's for a participant only available to an 'engine_worker'
250
+ # (block participants, stateful participants)
251
+ #
263
252
  def cannot_handle (msg)
264
253
 
265
254
  return false if msg['action'] != 'dispatch'
@@ -322,6 +311,7 @@ module Ruote
322
311
  raise_unknown_expression_error(exp_hash) unless exp_class
323
312
 
324
313
  exp = exp_class.new(@context, exp_hash.merge!('original_tree' => tree))
314
+
325
315
  exp.initial_persist
326
316
  exp.do_apply
327
317
  end
@@ -357,11 +347,8 @@ module Ruote
357
347
  tree[1]['original_ref'] = tree[0] if key != tree[0]
358
348
 
359
349
  if sub
360
-
361
350
  [ Ruote::Exp::SubprocessExpression, [ 'subprocess', *tree[1..2] ] ]
362
-
363
351
  else
364
-
365
352
  [ Ruote::Exp::ParticipantExpression, [ 'participant', *tree[1..2] ] ]
366
353
  end
367
354
  else
@@ -43,13 +43,47 @@ module Ruote
43
43
 
44
44
  @h = h
45
45
  class << @h; include Ruote::HashDot; end
46
+
47
+ #class << @h['fields']
48
+ # alias_method :__get, :[]
49
+ # alias_method :__set, :[]=
50
+ # def [] (key)
51
+ # __get(key.to_s)
52
+ # end
53
+ # def []= (key, value)
54
+ # __set(key.to_s, value)
55
+ # end
56
+ #end
57
+ # indifferent access, not activated for now
46
58
  end
47
59
 
60
+ # Returns the underlying Hash instance.
61
+ #
48
62
  def to_h
49
63
 
50
64
  @h
51
65
  end
52
66
 
67
+ # Returns the String id for this workitem (something like
68
+ # "0_0!!20100507-wagamama").
69
+ #
70
+ # It's in fact a shortcut for
71
+ #
72
+ # Ruote::FlowExpressionId.to_storage_id(h.fei)
73
+ #
74
+ def sid
75
+
76
+ Ruote::FlowExpressionId.to_storage_id(h.fei)
77
+ end
78
+
79
+ # Returns the "workflow instance id" (unique process instance id) of
80
+ # the process instance which issued this workitem.
81
+ #
82
+ def wfid
83
+
84
+ h.fei['wfid']
85
+ end
86
+
53
87
  # Returns a Ruote::FlowExpressionId instance.
54
88
  #
55
89
  def fei
@@ -170,6 +204,36 @@ module Ruote
170
204
 
171
205
  Ruote.set(@h['fields'], key, value)
172
206
  end
207
+
208
+ # Shortcut for wi.fields['__timed_out__']
209
+ #
210
+ def timed_out
211
+
212
+ @h['fields']['__timed_out__']
213
+ end
214
+
215
+ # Shortcut for wi.fields['__error__']
216
+ #
217
+ def error
218
+
219
+ @h['fields']['__error__']
220
+ end
221
+
222
+ # Shortcut for wi.fields['params']
223
+ #
224
+ # When a participant is invoked like in
225
+ #
226
+ # participant :ref => 'toto', :task => 'x"
227
+ #
228
+ # then
229
+ #
230
+ # p workitem.params
231
+ # # => { 'ref' => 'toto', 'task' => 'x' }
232
+ #
233
+ def params
234
+
235
+ @h['fields']['params']
236
+ end
173
237
  end
174
238
  end
175
239
 
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{ruote}
8
- s.version = "2.1.9"
8
+ s.version = "2.1.10"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["John Mettraux", "Kenneth Kalmer", "Torsten Schoenebaum"]
12
- s.date = %q{2010-03-23}
12
+ s.date = %q{2010-06-15}
13
13
  s.description = %q{
14
14
  ruote is an open source ruby workflow engine.
15
15
  }
@@ -35,6 +35,7 @@ ruote is an open source ruby workflow engine.
35
35
  "lib/ruote/engine.rb",
36
36
  "lib/ruote/engine/process_error.rb",
37
37
  "lib/ruote/engine/process_status.rb",
38
+ "lib/ruote/error_handler.rb",
38
39
  "lib/ruote/evt/tracker.rb",
39
40
  "lib/ruote/exp/command.rb",
40
41
  "lib/ruote/exp/commanded.rb",
@@ -79,7 +80,6 @@ ruote is an open source ruby workflow engine.
79
80
  "lib/ruote/fei.rb",
80
81
  "lib/ruote/id/mnemo_wfid_generator.rb",
81
82
  "lib/ruote/id/wfid_generator.rb",
82
- "lib/ruote/log/fs_history.rb",
83
83
  "lib/ruote/log/storage_history.rb",
84
84
  "lib/ruote/log/test_logger.rb",
85
85
  "lib/ruote/log/wait_logger.rb",
@@ -131,6 +131,7 @@ ruote is an open source ruby workflow engine.
131
131
  "test/functional/base.rb",
132
132
  "test/functional/concurrent_base.rb",
133
133
  "test/functional/crunner.rb",
134
+ "test/functional/crunner.sh",
134
135
  "test/functional/ct_0_concurrence.rb",
135
136
  "test/functional/ct_1_iterator.rb",
136
137
  "test/functional/ct_2_cancel.rb",
@@ -189,13 +190,17 @@ ruote is an open source ruby workflow engine.
189
190
  "test/functional/ft_2_errors.rb",
190
191
  "test/functional/ft_30_smtp_participant.rb",
191
192
  "test/functional/ft_31_part_blocking.rb",
192
- "test/functional/ft_32_fs_history.rb",
193
193
  "test/functional/ft_33_participant_subprocess_priority.rb",
194
194
  "test/functional/ft_34_cursor_rewind.rb",
195
195
  "test/functional/ft_35_add_service.rb",
196
196
  "test/functional/ft_36_storage_history.rb",
197
197
  "test/functional/ft_37_engine_participant.rb",
198
+ "test/functional/ft_38_participant_more.rb",
199
+ "test/functional/ft_39_wait_for.rb",
198
200
  "test/functional/ft_3_participant_registration.rb",
201
+ "test/functional/ft_40_participant_on_reply.rb",
202
+ "test/functional/ft_41_participants.rb",
203
+ "test/functional/ft_42_storage_copy.rb",
199
204
  "test/functional/ft_4_cancel.rb",
200
205
  "test/functional/ft_5_on_error.rb",
201
206
  "test/functional/ft_6_on_cancel.rb",
@@ -212,7 +217,7 @@ ruote is an open source ruby workflow engine.
212
217
  "test/functional/rtest.rb",
213
218
  "test/functional/storage_helper.rb",
214
219
  "test/functional/test.rb",
215
- "test/mpc_test.rb",
220
+ "test/functional/vertical.rb",
216
221
  "test/path_helper.rb",
217
222
  "test/pdef.xml",
218
223
  "test/test.rb",
@@ -243,7 +248,7 @@ ruote is an open source ruby workflow engine.
243
248
  s.rdoc_options = ["--charset=UTF-8"]
244
249
  s.require_paths = ["lib"]
245
250
  s.rubyforge_project = %q{ruote}
246
- s.rubygems_version = %q{1.3.6}
251
+ s.rubygems_version = %q{1.3.5}
247
252
  s.summary = %q{an open source ruby workflow engine}
248
253
  s.test_files = [
249
254
  "test/test.rb"
@@ -254,8 +259,8 @@ ruote is an open source ruby workflow engine.
254
259
  s.specification_version = 3
255
260
 
256
261
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
257
- s.add_runtime_dependency(%q<rufus-json>, [">= 0.2.0"])
258
- s.add_runtime_dependency(%q<rufus-cloche>, [">= 0.1.16"])
262
+ s.add_runtime_dependency(%q<rufus-json>, [">= 0.2.2"])
263
+ s.add_runtime_dependency(%q<rufus-cloche>, [">= 0.1.17"])
259
264
  s.add_runtime_dependency(%q<rufus-dollar>, [">= 0"])
260
265
  s.add_runtime_dependency(%q<rufus-lru>, [">= 0"])
261
266
  s.add_runtime_dependency(%q<rufus-mnemo>, [">= 1.1.0"])
@@ -268,8 +273,8 @@ ruote is an open source ruby workflow engine.
268
273
  s.add_development_dependency(%q<mailtrap>, [">= 0"])
269
274
  s.add_development_dependency(%q<jeweler>, [">= 0"])
270
275
  else
271
- s.add_dependency(%q<rufus-json>, [">= 0.2.0"])
272
- s.add_dependency(%q<rufus-cloche>, [">= 0.1.16"])
276
+ s.add_dependency(%q<rufus-json>, [">= 0.2.2"])
277
+ s.add_dependency(%q<rufus-cloche>, [">= 0.1.17"])
273
278
  s.add_dependency(%q<rufus-dollar>, [">= 0"])
274
279
  s.add_dependency(%q<rufus-lru>, [">= 0"])
275
280
  s.add_dependency(%q<rufus-mnemo>, [">= 1.1.0"])
@@ -283,8 +288,8 @@ ruote is an open source ruby workflow engine.
283
288
  s.add_dependency(%q<jeweler>, [">= 0"])
284
289
  end
285
290
  else
286
- s.add_dependency(%q<rufus-json>, [">= 0.2.0"])
287
- s.add_dependency(%q<rufus-cloche>, [">= 0.1.16"])
291
+ s.add_dependency(%q<rufus-json>, [">= 0.2.2"])
292
+ s.add_dependency(%q<rufus-cloche>, [">= 0.1.17"])
288
293
  s.add_dependency(%q<rufus-dollar>, [">= 0"])
289
294
  s.add_dependency(%q<rufus-lru>, [">= 0"])
290
295
  s.add_dependency(%q<rufus-mnemo>, [">= 1.1.0"])