openwferu 0.9.13 → 0.9.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. data/examples/bigflow.rb +19 -0
  2. data/examples/csv_weather.rb +23 -0
  3. data/examples/engine_template.rb +7 -0
  4. data/lib/openwfe/contextual.rb +0 -2
  5. data/lib/openwfe/engine/engine.rb +137 -34
  6. data/lib/openwfe/engine/file_persisted_engine.rb +0 -5
  7. data/lib/openwfe/exceptions.rb +0 -2
  8. data/lib/openwfe/expool/errorjournal.rb +83 -7
  9. data/lib/openwfe/expool/expressionpool.rb +279 -60
  10. data/lib/openwfe/expool/expstorage.rb +7 -6
  11. data/lib/openwfe/expool/yamlexpstorage.rb +17 -14
  12. data/lib/openwfe/expressions/condition.rb +10 -7
  13. data/lib/openwfe/expressions/environment.rb +11 -1
  14. data/lib/openwfe/expressions/fe_command.rb +14 -1
  15. data/lib/openwfe/expressions/fe_cron.rb +29 -14
  16. data/lib/openwfe/expressions/fe_define.rb +26 -1
  17. data/lib/openwfe/expressions/fe_iterator.rb +2 -0
  18. data/lib/openwfe/expressions/fe_losfor.rb +20 -15
  19. data/lib/openwfe/expressions/fe_misc.rb +0 -2
  20. data/lib/openwfe/expressions/fe_participant.rb +78 -24
  21. data/lib/openwfe/expressions/fe_reserve.rb +0 -2
  22. data/lib/openwfe/expressions/fe_sleep.rb +0 -4
  23. data/lib/openwfe/expressions/fe_subprocess.rb +34 -0
  24. data/lib/openwfe/expressions/fe_value.rb +46 -4
  25. data/lib/openwfe/expressions/fe_wait.rb +0 -2
  26. data/lib/openwfe/expressions/flowexpression.rb +39 -9
  27. data/lib/openwfe/expressions/raw.rb +73 -48
  28. data/lib/openwfe/expressions/raw_prog.rb +45 -15
  29. data/lib/openwfe/expressions/simplerep.rb +54 -7
  30. data/lib/openwfe/expressions/time.rb +5 -2
  31. data/lib/openwfe/expressions/timeout.rb +0 -2
  32. data/lib/openwfe/flowexpressionid.rb +26 -2
  33. data/lib/openwfe/participants/enoparticipants.rb +6 -1
  34. data/lib/openwfe/participants/participant.rb +0 -2
  35. data/lib/openwfe/participants/participantmap.rb +21 -7
  36. data/lib/openwfe/participants/participants.rb +29 -0
  37. data/lib/openwfe/rest/exception.rb +0 -2
  38. data/lib/openwfe/storage/yamlfilestorage.rb +4 -1
  39. data/lib/openwfe/util/dollar.rb +0 -2
  40. data/lib/openwfe/util/lru.rb +0 -2
  41. data/lib/openwfe/util/observable.rb +1 -1
  42. data/lib/openwfe/util/scheduler.rb +4 -4
  43. data/lib/openwfe/util/schedulers.rb +0 -2
  44. data/lib/openwfe/util/workqueue.rb +34 -91
  45. data/lib/openwfe/utils.rb +35 -28
  46. data/lib/openwfe/version.rb +1 -1
  47. data/lib/openwfe/workitem.rb +1 -1
  48. data/test/clone_test.rb +51 -0
  49. data/test/concurrence_test.rb +78 -0
  50. data/test/cron_test_2.rb +50 -0
  51. data/test/flowtestbase.rb +40 -12
  52. data/test/ft_21_cron.rb +32 -6
  53. data/test/ft_26_load.rb +8 -2
  54. data/test/ft_26c_load.rb +19 -0
  55. data/test/ft_27_getflowpos.rb +4 -4
  56. data/test/ft_2_concurrence.rb +14 -9
  57. data/test/ft_32_journal.rb +1 -1
  58. data/test/ft_32c_journal.rb +3 -2
  59. data/test/ft_32d_journal.rb +2 -1
  60. data/test/ft_34_cancelwfid.rb +7 -3
  61. data/test/ft_35_localdefs.rb +13 -0
  62. data/test/ft_38_tag.rb +8 -6
  63. data/test/ft_49_condition.rb +7 -1
  64. data/test/ft_55_ptimeout.rb +13 -14
  65. data/test/ft_57_a.rb +17 -0
  66. data/test/ft_58_ejournal.rb +3 -3
  67. data/test/ft_59_ps.rb +6 -6
  68. data/test/ft_60_ecancel.rb +3 -5
  69. data/test/ft_61_elsub.rb +2 -4
  70. data/test/ft_63_pause.rb +122 -0
  71. data/test/ft_64_alias.rb +102 -0
  72. data/test/ft_64_clone.rb +69 -0
  73. data/test/ft_65_stringlaunch.rb +61 -0
  74. data/test/ft_66_subforget.rb +70 -0
  75. data/test/ft_67_schedlaunch.rb +102 -0
  76. data/test/ft_68_ifparticipant.rb +70 -0
  77. data/test/ft_69_cancelmissing.rb +49 -0
  78. data/test/ft_6_lambda.rb +23 -3
  79. data/test/ft_70_lookupvar.rb +55 -0
  80. data/test/ft_7_lose.rb +1 -1
  81. data/test/ft_tests.rb +10 -1
  82. data/test/hparticipant_test.rb +6 -6
  83. data/test/param_test.rb +1 -1
  84. data/test/{rake_test.rb → rake_ltest.rb} +9 -2
  85. data/test/rake_qtest.rb +3 -1
  86. data/test/raw_prog_test.rb +11 -3
  87. data/test/restart_sleep_test.rb +44 -6
  88. data/test/ruby_procdef_test.rb +129 -0
  89. data/test/rutest_utils.rb +1 -0
  90. data/test/sec_test.rb +3 -3
  91. metadata +19 -4
@@ -0,0 +1,19 @@
1
+ #
2
+ # just a sample
3
+ #
4
+
5
+ class BigFlow0 < OpenWFE::ProcessDefinition
6
+
7
+ sequence do
8
+ alpha
9
+ concurrence do
10
+ bravo
11
+ cursor do
12
+ alpha
13
+ bravo
14
+ end
15
+ alpha :activity => "brush teeth"
16
+ end
17
+ bravo
18
+ end
19
+ end
@@ -0,0 +1,23 @@
1
+
2
+ require 'rubygems'
3
+ require 'openwfe/extras/util/csvtable'
4
+
5
+ include OpenWFE::Extras
6
+
7
+ $table = CsvTable.new("http://spreadsheets.google.com/pub?key=pCkopoeZwCNsMWOVeDjR1TQ&output=csv&gid=0")
8
+
9
+ def decide (hash)
10
+
11
+ $table.transform hash
12
+
13
+ puts " weather : #{hash['weather']}, month : #{hash['month']}"
14
+ puts " => take umbrella ? #{hash['take_umbrella?']}"
15
+ puts
16
+ end
17
+
18
+ puts
19
+
20
+ decide({ "weather" => "raining", "month" => "december" })
21
+ decide({ "weather" => "sunny", "month" => "december" })
22
+ decide({ "weather" => "cloudy", "month" => "may" })
23
+
@@ -201,6 +201,13 @@ end
201
201
  # the workitem to it over TCP
202
202
 
203
203
 
204
+ engine.reschedule
205
+ #
206
+ # this method has to be called after all the participants have been
207
+ # added, it looks for temporal expressions (sleep, cron, ...) to
208
+ # reschedule.
209
+
210
+
204
211
  #
205
212
  # === joining the engine's scheduler thread
206
213
  #
@@ -30,8 +30,6 @@
30
30
  # POSSIBILITY OF SUCH DAMAGE.
31
31
  #++
32
32
  #
33
- # $Id: definitions.rb 2725 2006-06-02 13:26:32Z jmettraux $
34
- #
35
33
 
36
34
  #
37
35
  # "made in Japan"
@@ -143,6 +143,7 @@ module OpenWFE
143
143
  # have been added.
144
144
  #
145
145
  def reschedule
146
+
146
147
  get_expression_pool.reschedule()
147
148
  end
148
149
 
@@ -158,6 +159,7 @@ module OpenWFE
158
159
  # This method can be useful in some scenarii though.
159
160
  #
160
161
  def pre_launch_check (launchitem)
162
+
161
163
  get_expression_pool.prepare_raw_expression(launchitem)
162
164
  end
163
165
 
@@ -174,31 +176,28 @@ module OpenWFE
174
176
  # Returns the FlowExpressionId instance of the expression at the
175
177
  # root of the newly launched process.
176
178
  #
177
- def launch (launch_object)
178
-
179
- launchitem = if launch_object.kind_of?(OpenWFE::LaunchItem)
180
-
181
- launch_object
182
-
183
- elsif launch_object.kind_of?(Class)
184
-
185
- LaunchItem.new launch_object
186
-
187
- elsif launch_object.kind_of? String
188
-
189
- li = OpenWFE::LaunchItem.new
190
-
191
- if launch_object[0, 1] == '<'
192
- li.workflowDefinitionUrl = "field:__definition"
193
- li['definition'] = launch_object
194
- else
195
- li.workflowDefinitionUrl = launch_object
196
- end
179
+ # Options for scheduled launches like :at, :in and :cron are accepted
180
+ # via the 'options' optional parameter.
181
+ # For example :
182
+ #
183
+ # engine.launch(launch_item)
184
+ # # will launch immediately
185
+ #
186
+ # engine.launch(launch_item, :in => "1d20m")
187
+ # # will launch in one day and twenty minutes
188
+ #
189
+ # engine.launch(launch_item, :at => "Tue Sep 11 20:23:02 +0900 2007")
190
+ # # will launch at that point in time
191
+ #
192
+ # engine.launch(launch_item, :cron => "0 5 * * *")
193
+ # # will launch that same process every day,
194
+ # # five minutes after midnight (see "man 5 crontab")
195
+ #
196
+ def launch (launch_object, options={})
197
197
 
198
- li
199
- end
198
+ launchitem = extract_launchitem launch_object
200
199
 
201
- fei = get_expression_pool.launch launchitem
200
+ fei = get_expression_pool.launch launchitem, options
202
201
 
203
202
  fei.dup
204
203
  #
@@ -231,6 +230,9 @@ module OpenWFE
231
230
  end
232
231
  end
233
232
 
233
+ alias :forward :reply
234
+ alias :proceed :reply
235
+
234
236
  #
235
237
  # Registers a participant in this [embedded] engine.
236
238
  # This method is a shortcut to the ParticipantMap method
@@ -422,18 +424,18 @@ module OpenWFE
422
424
  t = Thread.new { Thread.stop }
423
425
 
424
426
  to = get_expression_pool.add_observer(:terminate) do |c, fe, wi|
425
- t.wakeup if fe.fei.workflow_instance_id == wfid
427
+ t.wakeup if (fe.fei.workflow_instance_id == wfid and t.alive?)
426
428
  end
427
- te = get_expression_pool.add_observer(:error) do |c, fei, m, wi, se|
428
- t.wakeup if fei.parent_wfid == wfid
429
+ te = get_expression_pool.add_observer(:error) do |c, fei, m, i, e|
430
+ t.wakeup if (fei.parent_wfid == wfid and t.alive?)
429
431
  end
430
432
 
431
- ldebug { "wait_for() #{wfid}" }
433
+ linfo { "wait_for() #{wfid}" }
432
434
 
433
435
  t.join
434
436
 
435
- get_expression_pool.remove_observer to, :terminate
436
- get_expression_pool.remove_observer te, :error
437
+ get_expression_pool.remove_observer(to, :terminate)
438
+ get_expression_pool.remove_observer(te, :error)
437
439
  #
438
440
  # it would work as well without specifying the channel,
439
441
  # but it's thus a little bit faster
@@ -448,7 +450,7 @@ module OpenWFE
448
450
  # located (waiting certainly) and the errors the process currently
449
451
  # has (hopefully none).
450
452
  #
451
- def get_process_status (wfid=nil)
453
+ def list_process_status (wfid=nil)
452
454
 
453
455
  wfid = to_wfid(wfid) if wfid
454
456
 
@@ -475,6 +477,21 @@ module OpenWFE
475
477
  result
476
478
  end
477
479
 
480
+ #
481
+ # list_process_status() will be deprecated at release 1.0.0
482
+ #
483
+ alias :get_process_status :list_process_status
484
+
485
+ #
486
+ # Returns the process status of one given process instance.
487
+ #
488
+ def process_status (wfid)
489
+
490
+ wfid = to_wfid(wfid)
491
+
492
+ list_process_status(wfid).values[0]
493
+ end
494
+
478
495
  #--
479
496
  # METHODS FROM THE EXPRESSION POOL
480
497
  #
@@ -546,6 +563,48 @@ module OpenWFE
546
563
  get_expression_pool.forget(exp_or_fei)
547
564
  end
548
565
 
566
+ #
567
+ # Pauses a process (sets its /__paused__ variable to true).
568
+ #
569
+ def pause_process (wfid)
570
+
571
+ get_expression_pool.pause_process(wfid)
572
+ end
573
+
574
+ #
575
+ # Restarts a process : removes its 'paused' flag (variable) and makes
576
+ # sure to 'replay' events (replies) that came for it while it was
577
+ # in pause.
578
+ #
579
+ def resume_process (wfid)
580
+
581
+ get_expression_pool.resume_process(wfid)
582
+ end
583
+
584
+ #
585
+ # Looks up a process variable in a process.
586
+ # If fei_or_wfid is not given, will simply look in the
587
+ # 'engine environment' (where the top level variables '//' do reside).
588
+ #
589
+ def lookup_variable (var_name, fei_or_wfid=nil)
590
+
591
+ return get_expression_pool.fetch_engine_environment[var_name] \
592
+ unless fei_or_wfid
593
+
594
+ exp = if fei_or_wfid.is_a?(String)
595
+
596
+ get_expression_pool.fetch_root(fei_or_wfid)
597
+
598
+ else
599
+
600
+ get_expression_pool.fetch_expression(fei_or_wfid)
601
+ end
602
+
603
+ raise "no expression found for '#{fei_or_wfid.to_s}'" unless exp
604
+
605
+ exp.lookup_variable var_name
606
+ end
607
+
549
608
  protected
550
609
 
551
610
  #--
@@ -633,6 +692,38 @@ module OpenWFE
633
692
  init_service(S_ERROR_JOURNAL, InMemoryErrorJournal)
634
693
  end
635
694
 
695
+ #
696
+ # Turns the raw launch request info into a LaunchItem instance.
697
+ #
698
+ def extract_launchitem (launch_object)
699
+
700
+ if launch_object.kind_of?(OpenWFE::LaunchItem)
701
+
702
+ launch_object
703
+
704
+ elsif launch_object.kind_of?(Class)
705
+
706
+ LaunchItem.new launch_object
707
+
708
+ elsif launch_object.kind_of?(String)
709
+
710
+ li = OpenWFE::LaunchItem.new
711
+
712
+ #if launch_object[0, 1] == '<' or launch_object.match("\n")
713
+ if launch_object[0, 1] == '<' or launch_object.index("\n")
714
+
715
+ li.workflow_definition_url = "field:__definition"
716
+ li['__definition'] = launch_object
717
+
718
+ else
719
+
720
+ li.workflow_definition_url = launch_object
721
+ end
722
+
723
+ li
724
+ end
725
+ end
726
+
636
727
  end
637
728
 
638
729
  #
@@ -659,7 +750,7 @@ module OpenWFE
659
750
  attr_reader :expressions
660
751
 
661
752
  #
662
- # a hash whose values are ProcessError instances, the keys
753
+ # A hash whose values are ProcessError instances, the keys
663
754
  # are FlowExpressionId instances (fei) (identifying the expressions
664
755
  # that are concerned with the error)
665
756
  #
@@ -671,6 +762,15 @@ module OpenWFE
671
762
  @errors = {}
672
763
  end
673
764
 
765
+ #
766
+ # Returns true if the process is in pause.
767
+ #
768
+ def paused?
769
+
770
+ exp = @expressions[0]
771
+ exp != nil and exp.paused?
772
+ end
773
+
674
774
  #
675
775
  # this method is used by Engine.get_process_status() when
676
776
  # it prepares its results.
@@ -695,7 +795,8 @@ module OpenWFE
695
795
  @expressions.each do |fexp|
696
796
  s << " #{fexp.fei}\n"
697
797
  end
698
- s << " errors : #{@errors.size}"
798
+ s << " errors : #{@errors.size}\n"
799
+ s << " paused : #{paused?}"
699
800
  s
700
801
  end
701
802
 
@@ -751,8 +852,8 @@ module OpenWFE
751
852
  def pretty_print_process_status (ps)
752
853
 
753
854
  s = ""
754
- s << "process_id | name | rev | brn | err\n"
755
- s << "--------------------+-------------------+---------+-----+-----\n"
855
+ s << "process_id | name | rev | brn | err | paused? \n"
856
+ s << "--------------------+-------------------+---------+-----+-----+---------\n"
756
857
 
757
858
  ps.keys.sort.each do |wfid|
758
859
 
@@ -769,6 +870,8 @@ module OpenWFE
769
870
  s << "%3s" % status.expressions.size.to_s[0, 3]
770
871
  s << " | "
771
872
  s << "%3s" % status.errors.size.to_s[0, 3]
873
+ s << " | "
874
+ s << "%5s" % status.paused?.to_s
772
875
  s << "\n"
773
876
  end
774
877
  s
@@ -30,8 +30,6 @@
30
30
  # POSSIBILITY OF SUCH DAMAGE.
31
31
  #++
32
32
  #
33
- # $Id: definitions.rb 2725 2006-06-02 13:26:32Z jmettraux $
34
- #
35
33
 
36
34
  #
37
35
  # "made in Japan"
@@ -64,8 +62,6 @@ module OpenWFE
64
62
  #
65
63
  def build_expression_storage ()
66
64
 
67
- @application_context[:work_directory] = "./work"
68
-
69
65
  init_service(S_EXPRESSION_STORAGE, YamlFileExpressionStorage)
70
66
  end
71
67
 
@@ -93,7 +89,6 @@ module OpenWFE
93
89
  def build_expression_storage ()
94
90
 
95
91
  @application_context[:expression_cache_size] = 1000
96
- @application_context[:work_directory] = "./work"
97
92
 
98
93
  init_service(
99
94
  S_EXPRESSION_STORAGE,
@@ -30,8 +30,6 @@
30
30
  # POSSIBILITY OF SUCH DAMAGE.
31
31
  #++
32
32
  #
33
- # $Id: workitem.rb 3555 2006-11-13 00:47:53Z jmettraux $
34
- #
35
33
 
36
34
  #
37
35
  # Made in Japan
@@ -80,10 +80,15 @@ module OpenWFE
80
80
  #
81
81
  attr_reader :stacktrace
82
82
 
83
+ #
84
+ # The error class (String) of the top level error
85
+ #
86
+ attr_reader :error_class
87
+
83
88
  def initialize (*args)
84
89
 
85
90
  @date = Time.new
86
- @fei, @message, @workitem, @stacktrace = args
91
+ @fei, @message, @workitem, @error_class, @stacktrace = args
87
92
  end
88
93
 
89
94
  #
@@ -103,13 +108,34 @@ module OpenWFE
103
108
  def to_s
104
109
  s = ""
105
110
  s << "-- #{self.class.name} --\n"
106
- s << " date : #{@date}\n"
107
- s << " fei : #{@fei}\n"
108
- s << " message : #{@message}\n"
109
- s << " workitem : ...\n"
110
- s << " stacktrace : #{@stacktrace[0, 80]}\n"
111
+ s << " date : #{@date}\n"
112
+ s << " fei : #{@fei}\n"
113
+ s << " message : #{@message}\n"
114
+ s << " workitem : ...\n"
115
+ s << " error_class : #{@error_class}\n"
116
+ s << " stacktrace : #{@stacktrace[0, 80]}\n"
111
117
  s
112
118
  end
119
+
120
+ #
121
+ # Returns a hash
122
+ #
123
+ def hash
124
+ to_s.hash
125
+ #
126
+ # a bit costly but as it's only used by resume_process()...
127
+ end
128
+
129
+ #
130
+ # Returns true if the other instance is a ProcessError and is the
131
+ # same error as this one.
132
+ #
133
+ def == (other)
134
+ return false unless other.is_a?(ProcessError)
135
+ return to_s == other.to_s
136
+ #
137
+ # a bit costly but as it's only used by resume_process()...
138
+ end
113
139
  end
114
140
 
115
141
  #
@@ -129,7 +155,13 @@ module OpenWFE
129
155
  #
130
156
  # logs each error occuring in the expression pool
131
157
 
132
- record_error(ProcessError.new(*args))
158
+ begin
159
+
160
+ record_error(ProcessError.new(*args))
161
+
162
+ rescue Exception => e
163
+ lwarn { "*** process error : \n" + args.join("\n") }
164
+ end
133
165
  end
134
166
  end
135
167
 
@@ -241,6 +273,18 @@ module OpenWFE
241
273
  @per_processes.delete(wfid)
242
274
  end
243
275
 
276
+ #
277
+ # Removes a list of errors from the error journal.
278
+ #
279
+ def remove_errors (wfid, errors)
280
+
281
+ log = get_error_log wfid
282
+
283
+ errors.each do |e|
284
+ log.delete e
285
+ end
286
+ end
287
+
244
288
  #
245
289
  # Reads all the error logs currently stored.
246
290
  # Returns a hash wfid --> error list.
@@ -332,6 +376,38 @@ module OpenWFE
332
376
  File.delete(get_path(wfid))
333
377
  end
334
378
 
379
+ #
380
+ # Removes a list of errors from this error journal.
381
+ #
382
+ def remove_errors (wfid, errors)
383
+
384
+ # load all errors
385
+
386
+ log = get_error_log wfid
387
+
388
+ # remove the given errors
389
+
390
+ errors.each do |e|
391
+ log.delete e
392
+ end
393
+
394
+ # rewrite error file
395
+
396
+ path = get_path wfid
397
+
398
+ if log.size > 0
399
+
400
+ File.open(path, "w") do |f|
401
+ log.each do |e|
402
+ f.puts e.to_yaml
403
+ end
404
+ end
405
+ else
406
+
407
+ File.delete path
408
+ end
409
+ end
410
+
335
411
  #
336
412
  # Reads all the error logs currently stored.
337
413
  # Returns a hash wfid --> error list.