openwferu 0.9.4 → 0.9.5

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 (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