openwferu 0.9.4 → 0.9.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. data/examples/mano_tracker.rb +13 -6
  2. data/examples/quotereporter.rb +3 -2
  3. data/lib/openwfe/engine/engine.rb +31 -4
  4. data/lib/openwfe/engine/file_persisted_engine.rb +35 -9
  5. data/lib/openwfe/expool/expressionpool.rb +116 -67
  6. data/lib/openwfe/expool/expstorage.rb +142 -101
  7. data/lib/openwfe/expool/history.rb +7 -2
  8. data/lib/openwfe/expool/yamlexpstorage.rb +150 -6
  9. data/lib/openwfe/expressions/{fe_condition.rb → condition.rb} +4 -6
  10. data/lib/openwfe/expressions/expressionmap.rb +8 -0
  11. data/lib/openwfe/expressions/fe_cancel.rb +109 -0
  12. data/lib/openwfe/expressions/fe_concurrence.rb +252 -16
  13. data/lib/openwfe/expressions/fe_cursor.rb +8 -3
  14. data/lib/openwfe/{util/stoppable.rb → expressions/fe_do.rb} +42 -11
  15. data/lib/openwfe/expressions/fe_iterator.rb +4 -3
  16. data/lib/openwfe/expressions/fe_misc.rb +3 -2
  17. data/lib/openwfe/expressions/fe_participant.rb +5 -0
  18. data/lib/openwfe/expressions/fe_raw.rb +10 -2
  19. data/lib/openwfe/expressions/fe_subprocess.rb +1 -1
  20. data/lib/openwfe/expressions/fe_time.rb +43 -23
  21. data/lib/openwfe/expressions/fe_value.rb +1 -1
  22. data/lib/openwfe/expressions/flowexpression.rb +22 -22
  23. data/lib/openwfe/expressions/raw_prog.rb +20 -39
  24. data/lib/openwfe/expressions/raw_xml.rb +6 -6
  25. data/lib/openwfe/expressions/timeout.rb +8 -3
  26. data/lib/openwfe/expressions/wtemplate.rb +67 -0
  27. data/lib/openwfe/flowexpressionid.rb +4 -1
  28. data/lib/openwfe/participants/atomparticipants.rb +13 -1
  29. data/lib/openwfe/participants/enoparticipant.rb +66 -5
  30. data/lib/openwfe/participants/participantmap.rb +12 -0
  31. data/lib/openwfe/rudefinitions.rb +15 -3
  32. data/lib/openwfe/service.rb +4 -5
  33. data/lib/openwfe/storage/yamlfilestorage.rb +72 -45
  34. data/lib/openwfe/util/dollar.rb +17 -4
  35. data/lib/openwfe/util/lru.rb +154 -0
  36. data/lib/openwfe/util/otime.rb +26 -5
  37. data/lib/openwfe/util/scheduler.rb +44 -36
  38. data/lib/openwfe/util/schedulers.rb +4 -2
  39. data/lib/openwfe/utils.rb +62 -0
  40. data/lib/openwfe/version.rb +1 -1
  41. data/lib/openwfe/worklist/storeparticipant.rb +34 -5
  42. data/test/eno_test.rb +69 -0
  43. data/test/file_persistence_test.rb +13 -11
  44. data/test/flowtestbase.rb +29 -15
  45. data/test/ft_0.rb +2 -1
  46. data/test/ft_0b_sequence.rb +2 -1
  47. data/test/ft_0c_testname.rb +6 -5
  48. data/test/ft_0d_participant.rb +2 -1
  49. data/test/ft_10_loop.rb +11 -6
  50. data/test/ft_10b_loop2.rb +63 -0
  51. data/test/ft_11_ppd.rb +39 -13
  52. data/test/ft_12_blockparticipant.rb +2 -1
  53. data/test/ft_13_eno.rb +3 -2
  54. data/test/ft_14_subprocess.rb +2 -1
  55. data/test/ft_14b_subprocess.rb +2 -1
  56. data/test/ft_15_iterator.rb +2 -1
  57. data/test/ft_16_fqv.rb +2 -1
  58. data/test/ft_17_condition.rb +2 -1
  59. data/test/ft_18_pname.rb +2 -1
  60. data/test/ft_19_csv.rb +2 -1
  61. data/test/ft_1_unset.rb +14 -18
  62. data/test/ft_1b_unset.rb +39 -0
  63. data/test/ft_20_cron.rb +2 -1
  64. data/test/ft_21_cron.rb +2 -1
  65. data/test/ft_22_history.rb +7 -5
  66. data/test/ft_23_when.rb +2 -1
  67. data/test/ft_23b_when.rb +2 -1
  68. data/test/ft_24_def.rb +2 -1
  69. data/test/ft_25_cancel.rb +79 -0
  70. data/test/ft_26_load.rb +197 -0
  71. data/test/ft_2_concurrence.rb +89 -15
  72. data/test/ft_2b_concurrence.rb +152 -0
  73. data/test/ft_2c_concurrence.rb +39 -0
  74. data/test/ft_3_equals.rb +4 -3
  75. data/test/ft_4_misc.rb +4 -3
  76. data/test/ft_5_time.rb +2 -1
  77. data/test/ft_6_lambda.rb +2 -1
  78. data/test/ft_7_lose.rb +53 -17
  79. data/test/ft_8_forget.rb +7 -6
  80. data/test/ft_9_cursor.rb +8 -7
  81. data/test/hparticipant_test.rb +37 -14
  82. data/test/lru_test.rb +79 -0
  83. data/test/misc_test.rb +16 -0
  84. data/test/rake_qtest.rb +7 -0
  85. data/test/raw_prog_test.rb +0 -13
  86. data/test/rutest_utils.rb +15 -2
  87. data/test/scheduler_test.rb +31 -4
  88. data/test/timeout_test.rb +6 -2
  89. data/test/wfid_test.rb +68 -0
  90. metadata +169 -158
  91. data/lib/openwfe/expool/journalexpstorage.rb +0 -312
  92. data/lib/openwfe/util/lru_cache.rb +0 -149
@@ -45,7 +45,8 @@
45
45
  # for the context of this example
46
46
  #
47
47
 
48
- require 'openwfe/engine/engine'
48
+ #require 'openwfe/engine/engine'
49
+ require 'openwfe/engine/file_persisted_engine'
49
50
  require 'openwfe/expressions/raw_prog'
50
51
  require 'openwfe/participants/storeparticipant'
51
52
 
@@ -84,9 +85,14 @@ CREATIVES = [ "Jamie", "Jeff", "John", "Jeremy" ]
84
85
  #
85
86
  # instantiate the engine (a transient one is sufficient for the example)
86
87
 
87
- $engine = OpenWFE::engine.new
88
- #
89
- # setting up a transient engine
88
+ #$engine = OpenWFE::Engine.new
89
+ # no persistence
90
+
91
+ #$engine = OpenWFE::FilePersistedEngine.new
92
+ # persistence, but no caching (worst performance)
93
+
94
+ $engine = OpenWFE::CachedFilePersistedEngine.new
95
+ # persistence and performance
90
96
 
91
97
  $analyst_stores = {}
92
98
  $creative_stores = {}
@@ -95,8 +101,9 @@ $creative_stores = {}
95
101
 
96
102
  def add_stores (names, store_map)
97
103
  names.each do |name|
98
- hp = OpenWFE::HashParticipant.new
99
- $engine.register_participant(name, hp)
104
+ #hp = OpenWFE::HashParticipant.new
105
+ #$engine.register_participant(name, hp)
106
+ hp = $engine.register_participant(name, OpenWFE::YamlParticipant)
100
107
  store_map[name] = hp
101
108
  end
102
109
  end
@@ -53,9 +53,10 @@ class QuoteLookupFlow < OpenWFE::ProcessDefinition
53
53
  #participant :ref => "puts_workitem"
54
54
  #participant :ref => :puts_workitem
55
55
  #participant "puts_workitem"
56
- participant :puts_workitem
56
+ #participant :puts_workitem
57
+ puts_workitem
57
58
  #
58
- # the four notations are equivalent
59
+ # the five notations are equivalent
59
60
  end
60
61
  end
61
62
  end
@@ -67,15 +67,31 @@ module OpenWFE
67
67
 
68
68
  @application_context[@service_name] = self
69
69
 
70
+ $OWFE_LOG = Logger.new("engine.log") unless $OWFE_LOG
71
+
72
+ # build order matters.
73
+ #
74
+ # especially for the expstorage which 'observes' the expression
75
+ # pool and thus needs to be instantiated after it.
76
+
70
77
  build_scheduler()
71
78
 
72
79
  build_expression_map()
73
- build_expression_storage()
80
+
74
81
  build_expression_pool()
82
+ build_expression_storage()
75
83
 
76
84
  build_participant_map()
77
85
 
78
- $OWFE_LOG = Logger.new("engine.log") unless $LOG
86
+ #
87
+ # engine components are ready for operation, it's time to
88
+ # check persisted expressions (if any) to see if something
89
+ # has to be rescheduled (like a long time sleep expression or
90
+ # a cron)
91
+
92
+ get_expression_pool.reschedule()
93
+
94
+ linfo { "new() --- engine started --- #{self.object_id}" }
79
95
  end
80
96
 
81
97
  #
@@ -84,7 +100,13 @@ module OpenWFE
84
100
  # either a String containing the URL of the process definition
85
101
  # to launch (with an empty LaunchItem created on the fly).
86
102
  #
87
- def launch (launch_object)
103
+ # If async is set to true, the process will be launched asynchronously
104
+ # (in his own thread).
105
+ #
106
+ # Returns a FlowExpressionId instance or a tuple FlowExpressionId /
107
+ # Thread object if async is set to true.
108
+ #
109
+ def launch (launch_object, async=false)
88
110
 
89
111
  launchitem = nil
90
112
 
@@ -102,7 +124,7 @@ module OpenWFE
102
124
  end
103
125
  end
104
126
 
105
- get_expression_pool.launch(launchitem)
127
+ get_expression_pool.launch(launchitem, async)
106
128
  end
107
129
 
108
130
  #
@@ -120,6 +142,10 @@ module OpenWFE
120
142
  # This method is a shortcut to the ParticipantMap method
121
143
  # with the same name.
122
144
  #
145
+ # Returns the participant instance.
146
+ #
147
+ # see ParticipantMap#register_participant
148
+ #
123
149
  def register_participant (regex, participant=nil, &block)
124
150
 
125
151
  get_participant_map.register_participant(regex, participant, &block)
@@ -180,6 +206,7 @@ module OpenWFE
180
206
  end
181
207
 
182
208
  def build_scheduler ()
209
+ #ldebug { "build_scheduler()" }
183
210
  init_service(S_SCHEDULER, SchedulerService)
184
211
  end
185
212
 
@@ -51,16 +51,42 @@ module OpenWFE
51
51
  #
52
52
  class FilePersistedEngine < Engine
53
53
 
54
- #
55
- # Overrides the method already found in Engine with a persisted
56
- # expression storage
57
- #
58
- def build_expression_storage ()
54
+ protected
59
55
 
60
- @application_context[:work_directory] = "./work"
56
+ #
57
+ # Overrides the method already found in Engine with a persisted
58
+ # expression storage
59
+ #
60
+ def build_expression_storage ()
61
61
 
62
- init_service(S_EXPRESSION_STORAGE, YamlFileExpressionStorage)
63
- end
64
-
62
+ @application_context[:work_directory] = "./work"
63
+
64
+ init_service(S_EXPRESSION_STORAGE, YamlFileExpressionStorage)
65
+ end
66
+ end
67
+
68
+ #
69
+ # An engine with a cache in front of its file persisted expression storage.
70
+ #
71
+ class CachedFilePersistedEngine < Engine
72
+
73
+ protected
74
+
75
+ def build_expression_storage ()
76
+
77
+ @application_context[:expression_cache_size] = 1000
78
+ @application_context[:work_directory] = "./work"
79
+
80
+ init_service(
81
+ S_EXPRESSION_STORAGE,
82
+ CacheExpressionStorage)
83
+
84
+ #init_service(
85
+ # S_EXPRESSION_STORAGE + ".1",
86
+ # YamlFileExpressionStorage)
87
+ init_service(
88
+ S_EXPRESSION_STORAGE + ".1",
89
+ ThreadedYamlFileExpressionStorage)
90
+ end
65
91
  end
66
92
  end
@@ -49,8 +49,7 @@ require 'openwfe/service'
49
49
  require 'openwfe/logging'
50
50
  require 'openwfe/rudefinitions'
51
51
  require 'openwfe/flowexpressionid'
52
- require 'openwfe/util/stoppable'
53
- require 'openwfe/util/lru_cache'
52
+ require 'openwfe/util/lru'
54
53
  require 'openwfe/util/observable'
55
54
  require 'openwfe/expressions/environment'
56
55
  require 'openwfe/expressions/raw_xml'
@@ -72,7 +71,7 @@ module OpenWFE
72
71
  def initialize (application_context=nil)
73
72
  super()
74
73
  @application_context = application_context
75
- @monitors = LRUCache.new(MAX_MONITORS)
74
+ @monitors = LruHash.new(MAX_MONITORS)
76
75
  end
77
76
 
78
77
  def [] (key)
@@ -127,7 +126,6 @@ module OpenWFE
127
126
  ServiceMixin,
128
127
  MonitorMixin,
129
128
  OwfeServiceLocator,
130
- Stoppable,
131
129
  Observable
132
130
 
133
131
  @@last_given_instance_id = -1
@@ -144,16 +142,14 @@ module OpenWFE
144
142
 
145
143
  @observers = {}
146
144
 
147
- reschedule_a_bit_later
145
+ @stopped = false
148
146
  end
149
147
 
150
148
  #
151
149
  # Makes sure to call the do_stop() method of the Stoppable mixin
152
150
  #
153
151
  def stop
154
- # would an alias be better ?
155
- do_stop
156
-
152
+ @stopped = true
157
153
  onotify :stop
158
154
  end
159
155
 
@@ -169,24 +165,42 @@ module OpenWFE
169
165
  #
170
166
  # Instantiates a workflow definition and launches it.
171
167
  #
172
- def launch (launchitem)
168
+ # If async is set to true, the launch will occur in its own thread.
169
+ #
170
+ # Returns the FlowExpressionId instance of the root expression of
171
+ # the newly launched flow.
172
+ # If async is set to true, returns a tuple FlowExpressionId /
173
+ # Thread instance used.
174
+ #
175
+ def launch (launchitem, async=false)
173
176
 
174
177
  onotify :launch, launchitem.workflow_definition_url
175
178
 
176
- rawExpression = buildRawExpression(launchitem)
179
+ raw_expression = buildRawExpression(launchitem)
177
180
 
178
181
  wi = build_workitem(launchitem)
179
182
 
180
- rawExpression.apply(wi)
183
+ fei = raw_expression.fei
184
+
185
+ if async
186
+
187
+ t = OpenWFE::call_in_thread "launch()", self do
188
+ raw_expression.apply(wi)
189
+ end
190
+
191
+ return fei, t
192
+ end
181
193
 
182
- return wi.flow_expression_id
194
+ raw_expression.apply(wi)
195
+
196
+ return fei
183
197
  end
184
198
 
185
199
  #
186
200
  # launches a subprocess
187
201
  #
188
- def launch_template \
189
- (requesting_expression, template, workitem, params=nil)
202
+ def launch_template (
203
+ requesting_expression, sub_id, template, workitem, params=nil)
190
204
 
191
205
  #ldebug { "launch_template() of class #{template.class}" }
192
206
 
@@ -205,18 +219,28 @@ module OpenWFE
205
219
  rawexp = rawexp.dup()
206
220
  rawexp.fei = rawexp.fei.dup()
207
221
 
208
- if requesting_expression.kind_of? FlowExpressionId
222
+ if requesting_expression == nil
223
+
224
+ rawexp.parent_id = nil
225
+ rawexp.fei.workflow_instance_id = new_workflow_instance_id()
226
+
227
+ elsif requesting_expression.kind_of? FlowExpressionId
228
+
209
229
  rawexp.parent_id = requesting_expression
210
230
  rawexp.fei.workflow_instance_id = \
211
- "#{requesting_expression.workflow_instance_id}.0"
231
+ "#{requesting_expression.workflow_instance_id}.#{sub_id}"
232
+
212
233
  elsif requesting_expression.kind_of? String
234
+
213
235
  rawexp.parent_id = nil
214
236
  rawexp.fei.workflow_instance_id = \
215
- "#{requesting_expression}.0"
237
+ "#{requesting_expression}.${sub_id}"
238
+
216
239
  else # kind is FlowExpression
240
+
217
241
  rawexp.parent_id = requesting_expression.fei
218
242
  rawexp.fei.workflow_instance_id = \
219
- "#{requesting_expression.fei.workflow_instance_id}.0"
243
+ "#{requesting_expression.fei.workflow_instance_id}.#{sub_id}"
220
244
  end
221
245
 
222
246
  #ldebug do
@@ -242,11 +266,11 @@ module OpenWFE
242
266
 
243
267
  workitem.flow_expression_id = rawexp.fei
244
268
 
245
- rawexp.apply(workitem)
269
+ fei = rawexp.fei
246
270
 
247
- # why not : launch in a thread and reply immediately
271
+ rawexp.apply(workitem)
248
272
 
249
- return workitem.flow_expression_id
273
+ return fei
250
274
  end
251
275
 
252
276
  #
@@ -254,9 +278,15 @@ module OpenWFE
254
278
  # returns its body fei
255
279
  #
256
280
  def evaluate (rawExpression, workitem)
281
+
257
282
  exp = rawExpression.instantiate_real_expression(workitem)
258
283
  fei = exp.evaluate(workitem)
259
- remove(rawExpression)
284
+
285
+ #remove(rawExpression)
286
+ #
287
+ # not necessary, the raw expression gets overriden by
288
+ # the real expression
289
+
260
290
  return fei
261
291
  end
262
292
 
@@ -305,6 +335,19 @@ module OpenWFE
305
335
  return inflowitem
306
336
  end
307
337
 
338
+ #
339
+ # Given any expression of a process, cancels the complete process.
340
+ #
341
+ def cancel_flow (exp)
342
+
343
+ ldebug { "cancel_flow() from #{exp}" }
344
+
345
+ root = fetch_root(exp)
346
+ cancel(root)
347
+ end
348
+
349
+ alias :cancel_process :cancel_flow
350
+
308
351
  #
309
352
  # Forgets the given expression (makes sure to substitute its
310
353
  # parent_id with the GONE_PARENT_ID constant)
@@ -326,13 +369,12 @@ module OpenWFE
326
369
  #
327
370
  def reply_to_parent (exp, workitem)
328
371
 
329
- exp, fei = fetch(exp)
372
+ ldebug { "reply_to_parent() for #{exp.fei.to_debug_s}" }
330
373
 
331
- workitem.last_expression_id = fei
374
+ workitem.last_expression_id = exp.fei
332
375
 
333
- onotify :reply_to_parent, fei, workitem
376
+ onotify :reply_to_parent, exp.fei, workitem
334
377
 
335
- #remove(exp, workitem)
336
378
  remove(exp)
337
379
 
338
380
  #
@@ -383,9 +425,15 @@ module OpenWFE
383
425
  #
384
426
  def update (flowExpression)
385
427
 
428
+ t = Timer.new
429
+
386
430
  onotify :update, flowExpression.fei, flowExpression
387
431
 
388
- get_expression_storage()[flowExpression.fei] = flowExpression
432
+ #get_expression_storage()[flowExpression.fei] = flowExpression
433
+
434
+ ldebug { "update() took #{t.duration} ms" }
435
+
436
+ return flowExpression
389
437
  end
390
438
 
391
439
  #
@@ -399,6 +447,9 @@ module OpenWFE
399
447
  synchronize do
400
448
 
401
449
  fei = exp
450
+
451
+ #ldebug { "fetch() exp is of kind #{exp.class}" }
452
+
402
453
  if exp.kind_of? FlowExpression
403
454
  fei = exp.fei
404
455
  elsif not exp.kind_of? FlowExpressionId
@@ -424,6 +475,19 @@ module OpenWFE
424
475
  return exp
425
476
  end
426
477
 
478
+ #
479
+ # Fetches the root expression of a process (given any of its
480
+ # expressions).
481
+ #
482
+ def fetch_root (exp)
483
+ exp = fetch_expression(exp)
484
+ return exp unless exp.parent_id
485
+ return fetch_root(fetch_expression(exp.parent_id))
486
+ end
487
+
488
+ #
489
+ # Returns the engine environment (the top level environment)
490
+ #
427
491
  def fetch_engine_environment ()
428
492
  synchronize do
429
493
 
@@ -446,22 +510,26 @@ module OpenWFE
446
510
  #
447
511
  def remove (exp)
448
512
 
449
- exp, fei = fetch(exp)
513
+ #exp, fei = fetch(exp)
514
+
515
+ if exp.kind_of? FlowExpressionId
516
+ exp, _fei = fetch(exp)
517
+ end
450
518
 
451
519
  return if not exp
452
520
 
453
- ldebug { "remove() fe #{fei.to_debug_s}" }
521
+ ldebug { "remove() fe #{exp.fei.to_debug_s}" }
454
522
 
455
- onotify :remove, fei
523
+ onotify :remove, exp.fei
456
524
 
457
525
  synchronize do
458
526
 
459
- @monitors.delete(fei)
527
+ @monitors.delete(exp.fei)
460
528
 
461
- #get_expression_storage().remove(fei, workitem)
462
- get_expression_storage().delete(fei)
529
+ #get_expression_storage().delete(fei)
463
530
 
464
531
  if exp.owns_its_environment?
532
+
465
533
  remove_environment(exp.environment_id)
466
534
  end
467
535
 
@@ -474,19 +542,12 @@ module OpenWFE
474
542
  # to reschedule ones like 'sleep' or 'cron'.
475
543
  #
476
544
  def reschedule
545
+
546
+ return if @stopped
547
+
477
548
  synchronize do
478
549
 
479
- #if is_stopped?
480
- # linfo { "reschedule() skipped as expool is stopped" }
481
- # return
482
- #end
483
- #if get_scheduler.is_stopped?
484
- # linfo do
485
- # "reschedule() skipped as scheduler "+
486
- # "#{get_scheduler.object_id} is stopped"
487
- # end
488
- # return
489
- #end
550
+ t = OpenWFE::Timer.new
490
551
 
491
552
  ldebug { "reschedule() initiating..." }
492
553
 
@@ -499,7 +560,7 @@ module OpenWFE
499
560
  fe.reschedule(get_scheduler)
500
561
  end
501
562
 
502
- ldebug { "reschedule() done." }
563
+ ldebug { "reschedule() done. (took #{t.duration} ms)" }
503
564
  end
504
565
  end
505
566
 
@@ -527,25 +588,6 @@ module OpenWFE
527
588
 
528
589
  protected
529
590
 
530
- def reschedule_a_bit_later
531
- Thread.new do
532
- #
533
- # Just leaving some time for the initialize() to finish
534
- # and let the expression pool get registered in
535
- # the application context
536
- #
537
- begin
538
- sleep(0.001)
539
- reschedule()
540
- rescue
541
- lwarn do
542
- "reschedule() failed\n"+
543
- OpenWFE::exception_to_s($!)
544
- end
545
- end
546
- end
547
- end
548
-
549
591
  def evaluate_definition (raw_definition, workitem)
550
592
  expression = raw_definition.instantiate(workitem)
551
593
  end
@@ -558,7 +600,9 @@ module OpenWFE
558
600
 
559
601
  env.unbind()
560
602
 
561
- get_expression_storage().delete(environment_id)
603
+ #get_expression_storage().delete(environment_id)
604
+
605
+ onotify :remove, environment_id
562
606
  end
563
607
 
564
608
  def build_workitem (launchitem)
@@ -613,7 +657,7 @@ module OpenWFE
613
657
 
614
658
  if sDefinition.kind_of? Class
615
659
 
616
- return sDefinition.do_make(get_expression_map)
660
+ return sDefinition.do_make()
617
661
  end
618
662
 
619
663
  raise \
@@ -640,9 +684,14 @@ module OpenWFE
640
684
  def new_workflow_instance_id ()
641
685
 
642
686
  synchronize do
687
+
643
688
  wfid = OpenWFE::current_time_millis()
644
- wfid = wfid + 1 if wfid == @@last_given_instance_id
689
+
690
+ wfid = @@last_given_instance_id + 1 \
691
+ if wfid <= @@last_given_instance_id
692
+
645
693
  @@last_given_instance_id = wfid
694
+
646
695
  return wfid.to_s
647
696
  end
648
697
  end