flor 0.16.1 → 0.16.2

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/CREDITS.md +1 -0
  4. data/Makefile +1 -1
  5. data/README.md +82 -6
  6. data/lib/flor.rb +1 -1
  7. data/lib/flor/conf.rb +19 -6
  8. data/lib/flor/core/executor.rb +45 -16
  9. data/lib/flor/core/node.rb +4 -4
  10. data/lib/flor/core/procedure.rb +40 -0
  11. data/lib/flor/djan.rb +5 -2
  12. data/lib/flor/flor.rb +92 -7
  13. data/lib/flor/id.rb +19 -0
  14. data/lib/flor/migrations/0001_tables.rb +6 -6
  15. data/lib/flor/migrations/0005_pointer_content.rb +20 -0
  16. data/lib/flor/pcore/_apply.rb +103 -57
  17. data/lib/flor/pcore/_att.rb +15 -1
  18. data/lib/flor/pcore/_ref.rb +2 -1
  19. data/lib/flor/pcore/arith.rb +46 -9
  20. data/lib/flor/pcore/break.rb +1 -1
  21. data/lib/flor/pcore/case.rb +41 -0
  22. data/lib/flor/pcore/collect.rb +1 -1
  23. data/lib/flor/pcore/cursor.rb +1 -1
  24. data/lib/flor/pcore/define.rb +32 -6
  25. data/lib/flor/pcore/iterator.rb +12 -0
  26. data/lib/flor/pcore/on_cancel.rb +1 -1
  27. data/lib/flor/pcore/set.rb +14 -4
  28. data/lib/flor/punit/{ccollect.rb → c_collect.rb} +2 -2
  29. data/lib/flor/punit/c_each.rb +11 -0
  30. data/lib/flor/punit/c_for_each.rb +41 -0
  31. data/lib/flor/punit/c_iterator.rb +160 -0
  32. data/lib/flor/punit/c_map.rb +43 -0
  33. data/lib/flor/punit/concurrence.rb +43 -200
  34. data/lib/flor/punit/graft.rb +3 -2
  35. data/lib/flor/punit/m_ram.rb +281 -0
  36. data/lib/flor/unit.rb +1 -0
  37. data/lib/flor/unit/caller.rb +6 -1
  38. data/lib/flor/unit/executor.rb +17 -4
  39. data/lib/flor/unit/ganger.rb +12 -1
  40. data/lib/flor/unit/hloader.rb +251 -0
  41. data/lib/flor/unit/hook.rb +74 -15
  42. data/lib/flor/unit/hooker.rb +9 -12
  43. data/lib/flor/unit/loader.rb +41 -17
  44. data/lib/flor/unit/models.rb +54 -18
  45. data/lib/flor/unit/models/execution.rb +15 -4
  46. data/lib/flor/unit/models/pointer.rb +11 -0
  47. data/lib/flor/unit/scheduler.rb +126 -30
  48. data/lib/flor/unit/spooler.rb +5 -3
  49. data/lib/flor/unit/storage.rb +40 -13
  50. data/lib/flor/unit/waiter.rb +165 -26
  51. data/lib/flor/unit/wlist.rb +98 -5
  52. metadata +10 -4
  53. data/lib/flor/punit/cmap.rb +0 -112
@@ -14,21 +14,13 @@ module Flor
14
14
 
15
15
  def to_hook
16
16
 
17
- opts = {}
18
- opts[:consumed] = @h['consumed']
19
- opts[:point] = Flor.h_fetch_a(@h, 'points', 'point', nil)
20
- opts[:nid] = Flor.h_fetch_a(@h, 'nids', 'nid', nil)
21
- opts[:heap] = Flor.h_fetch_a(@h, 'heaps', 'heap', nil)
22
- opts[:heat] = Flor.h_fetch_a(@h, 'heats', 'heat', nil)
23
- #opts[:name] = data['names']
24
-
25
- #correct_points(opts)
26
- #
27
- # Necessary since "cancel" gets interpreted as
28
- # [ '_proc', { 'proc' => 'cancel' }, @line ]
29
- # ...
30
-
31
- [ "hook#{object_id}", opts, self, nil ]
17
+ if @h['class']
18
+ class_to_hook
19
+ elsif @h['instance']
20
+ instance_to_hook
21
+ else
22
+ classical_to_hook
23
+ end
32
24
  end
33
25
 
34
26
  def notify(executor, message)
@@ -56,6 +48,73 @@ module Flor
56
48
  # return point[1]['proc'] if point.is_a?(Array) && point[0] == '_proc'
57
49
  # point
58
50
  # end
51
+
52
+ def extract_filters(h)
53
+
54
+ r = {}
55
+ r[:consumed] = h['consumed']
56
+ r[:point] = Flor.h_fetch_a(h, 'points', 'point', nil)
57
+ r[:nid] = Flor.h_fetch_a(h, 'nids', 'nid', nil)
58
+ r[:heap] = Flor.h_fetch_a(h, 'heaps', 'heap', nil)
59
+ r[:heat] = Flor.h_fetch_a(h, 'heats', 'heat', nil)
60
+ #opts[:name] = data['names']
61
+
62
+ r
63
+ end
64
+
65
+ def class_to_hook
66
+
67
+ i = Flor::Hook.instantiate(@unit, @h['class'])
68
+
69
+ h = @h.dup
70
+ h.merge!(Flor.to_string_keyed_hash(i.opts)) if i.respond_to?(:opts)
71
+ opts = extract_filters(h)
72
+
73
+ [ "hooc#{object_id}", opts, i, nil ]
74
+ end
75
+
76
+ def instance_to_hook
77
+
78
+ i = @h['instance']
79
+
80
+ h = @h.dup
81
+ h.merge!(Flor.to_string_keyed_hash(i.opts)) if i.respond_to?(:opts)
82
+ opts = extract_filters(h)
83
+
84
+ [ "hooi#{object_id}", opts, i, nil ]
85
+ end
86
+
87
+ def classical_to_hook
88
+
89
+ opts = extract_filters(@h)
90
+
91
+ #correct_points(opts)
92
+ #
93
+ # Necessary since "cancel" gets interpreted as
94
+ # [ '_proc', { 'proc' => 'cancel' }, @line ]
95
+ # ...
96
+
97
+ [ "hook#{object_id}", opts, self, nil ]
98
+ end
99
+
100
+ class << self
101
+
102
+ def instantiate(unit, hook_class)
103
+
104
+ c =
105
+ case hook_class
106
+ when String then Flor.const_get(hook_class)
107
+ else hook_class
108
+ end
109
+ a =
110
+ case i = c.instance_method(:initialize).arity
111
+ when 0, 1 then [ unit ][0, i]
112
+ else []
113
+ end
114
+
115
+ c.new(*a)
116
+ end
117
+ end
59
118
  end
60
119
  end
61
120
 
@@ -9,6 +9,14 @@ module Flor
9
9
 
10
10
  @unit = unit
11
11
 
12
+ class << unit
13
+
14
+ def hook(*args, &block)
15
+
16
+ @hooker.add(*args, &block)
17
+ end
18
+ end
19
+
12
20
  @hooks = []
13
21
  end
14
22
 
@@ -46,7 +54,7 @@ module Flor
46
54
  end
47
55
  end
48
56
 
49
- hook = instantiate_hook(hook) if hook.is_a?(Class)
57
+ hook = Flor::Hook.instantiate(@unit, hook) if hook.is_a?(Class)
50
58
 
51
59
  @hooks << [ name, opts, hook, block ]
52
60
  end
@@ -73,17 +81,6 @@ module Flor
73
81
 
74
82
  protected
75
83
 
76
- def instantiate_hook(hook_class)
77
-
78
- a =
79
- case i = hook_class.instance_method(:initialize).arity
80
- when 0, 1 then [ @unit ][0, i]
81
- else []
82
- end
83
-
84
- hook_class.new(*a)
85
- end
86
-
87
84
  def o(opts, *keys)
88
85
 
89
86
  array = false
@@ -23,7 +23,7 @@ module Flor
23
23
  Dir[File.join(@root, '**/*.json')]
24
24
  .select { |f| f.index('/etc/variables/') }
25
25
  .collect { |pa| [ pa, expose_d(pa, {}) ] }
26
- .select { |pa, d| is_subdomain?(domain, d) }
26
+ .select { |pa, d| Flor.sub_domain?(d, domain) }
27
27
  .sort_by { |pa, d| d.count('.') }
28
28
  .inject({}) { |vars, (pa, _)| vars.merge!(eval(pa, {})) }
29
29
  end
@@ -48,7 +48,7 @@ module Flor
48
48
  path, _, _ = (Dir[File.join(@root, '**/*.{flo,flor}')])
49
49
  .select { |f| f.index('/lib/') }
50
50
  .collect { |pa| [ pa, *expose_dn(pa, opts) ] }
51
- .select { |pa, d, n| n == name && is_subdomain?(domain, d) }
51
+ .select { |pa, d, n| n == name && Flor.sub_domain?(d, domain) }
52
52
  .sort_by { |pa, d, n| d.count('.') }
53
53
  .last
54
54
 
@@ -62,12 +62,12 @@ module Flor
62
62
 
63
63
  domain, name = split_dn(domain, name)
64
64
 
65
- pat, _, nam = Dir[File.join(@root, '**/*.json')]
65
+ pat, _, nam = Dir[File.join(@root, '**/*.{json,rb}')]
66
66
  .select { |pa| pa.index('/lib/taskers/') }
67
67
  .collect { |pa| [ pa, *expose_dn(pa, {}) ] }
68
68
  .select { |pa, d, n|
69
- is_subdomain?(domain, [ d, n ].join('.')) ||
70
- (n == name && is_subdomain?(domain, d)) }
69
+ Flor.sub_domain?([ d, n ].join('.'), domain) ||
70
+ (n == name && Flor.sub_domain?(d, domain)) }
71
71
  .sort_by { |pa, d, n| d.count('.') }
72
72
  .last
73
73
 
@@ -87,7 +87,7 @@ module Flor
87
87
  conf
88
88
  end
89
89
 
90
- def hooks(domain, name=nil)
90
+ def hooks(domain)
91
91
 
92
92
  # NB: do not relativize path, because Ruby load path != cwd,
93
93
  # stay absolute for `require` and `load`
@@ -95,7 +95,7 @@ module Flor
95
95
  Dir[File.join(@root, '**/*.json')]
96
96
  .select { |f| f.index('/lib/hooks/') }
97
97
  .collect { |pa| [ pa, expose_d(pa, {}) ] }
98
- .select { |pa, d| is_subdomain?(domain, d) }
98
+ .select { |pa, d| Flor.sub_domain?(d, domain) }
99
99
  .sort_by { |pa, d| d.count('.') }
100
100
  .collect { |pa, d|
101
101
  eval(pa, {}).each_with_index { |h, i|
@@ -111,15 +111,6 @@ module Flor
111
111
 
112
112
  protected
113
113
 
114
- # is da a subdomain of db?
115
- #
116
- def is_subdomain?(da, db)
117
-
118
- da == db ||
119
- db == '' ||
120
- da[0, db.length + 1] == db + '.'
121
- end
122
-
123
114
  def split_dn(domain, name)
124
115
 
125
116
  if name
@@ -145,7 +136,7 @@ module Flor
145
136
  .sub(libregex, '/')
146
137
  .sub(/\/\z/, '')
147
138
  .sub(/\/(flo|flor|dot|hooks)\.json\z/, '')
148
- .sub(/\.(flo|flor|json)\z/, '')
139
+ .sub(/\.(flo|flor|json|rb)\z/, '')
149
140
  .sub(/\A\//, '')
150
141
  .gsub(/\//, '.')
151
142
  end
@@ -163,6 +154,9 @@ module Flor
163
154
 
164
155
  def eval(path, context)
165
156
 
157
+ ext =
158
+ File.extname(path)
159
+
166
160
  src =
167
161
  @mutex.synchronize do
168
162
 
@@ -171,13 +165,43 @@ module Flor
171
165
 
172
166
  if val && mt1 == mt0
173
167
  val
168
+ elsif ext == '.rb'
169
+ (@cache[path] = [ File.read(path), mt1 ]).first
174
170
  else
175
171
  (@cache[path] = [ Flor::ConfExecutor.load(path), mt1 ]).first
176
172
  end
177
173
  end
178
174
 
175
+ case ext
176
+ when '.rb' then eval_ruby(path, src, context)
177
+ else eval_json(path, src, context)
178
+ end
179
+ end
180
+
181
+ def eval_json(path, src, context)
182
+
179
183
  Flor::ConfExecutor.interpret(path, src, context)
180
184
  end
185
+
186
+ def eval_ruby(path, src, context)
187
+
188
+ ks = context.keys.select { |k| k.match(/\A[a-z][a-zA-Z0-9_]+\z/) }
189
+
190
+ s = StringIO.new
191
+ s << "lambda {\n"
192
+ ks.each { |k| s << k << " = " << context[k].inspect << "\n" }
193
+ s << src
194
+ s << "\n}.call\n"
195
+
196
+ r = Kernel.module_eval(s.string, path, - ks.size)
197
+
198
+ r = JSON.parse(JSON.dump(r)) #if r.keys.find { |k| k.is_a?(Symbol) }
199
+ #
200
+ # so that symbols may be used in the .rb file, but plain JSON-like
201
+ # string keys are on the output
202
+
203
+ r.merge!('_path' => path)
204
+ end
181
205
  end
182
206
  end
183
207
 
@@ -28,10 +28,46 @@ module Flor
28
28
 
29
29
  self.require_valid_table = false
30
30
 
31
+ class << self
32
+
33
+ attr_accessor :unit
34
+ end
35
+
36
+ def unit; self.class.unit; end
37
+ def storage; unit.storage; end
38
+
39
+ # Return a Flor::Execution instance linked to this model
40
+ #
41
+ def execution(reload=false)
42
+
43
+ exid = @values[:exid]; return nil unless exid
44
+
45
+ @execution = nil if reload
46
+
47
+ @execution ||= unit.executions[exid: exid]
48
+ end
49
+
50
+ # Returns the node hash linked to this model
51
+ #
52
+ def node(reload=false)
53
+
54
+ nid = @values[:nid]; return nil unless nid
55
+ exe = execution(reload); return nil unless exe
56
+
57
+ nodes = exe.data['nodes']; return nil unless nodes
58
+ nodes[nid]
59
+ end
60
+
61
+ def payload(reload=false)
62
+
63
+ nod = node(reload)
64
+ nod ? nod['payload'] : nil
65
+ end
66
+
31
67
  def _data
32
68
 
33
69
  d = Flor::Storage.from_blob(content)
34
- d['id'] = id
70
+ d['id'] = id if d.is_a?(Hash)
35
71
 
36
72
  d
37
73
  end
@@ -59,31 +95,31 @@ module Flor
59
95
  dir = File.dirname(__FILE__)
60
96
  MODELS.each { |m| require File.join(dir, 'models', "#{m.to_s[0..-2]}.rb") }
61
97
 
62
- class Storage
98
+ def self.add_model(key, parent_module=Flor, table_prefix='flor_')
63
99
 
64
- MODELS.each do |k|
100
+ Flor::Storage.send(:define_method, key) do
65
101
 
66
- define_method(k) do
102
+ s = self
103
+ c = Flor.to_camel_case(key.to_s[0..-2])
67
104
 
68
- s = self
69
- c = k.to_s[0..-2].capitalize
105
+ @models[key] ||=
106
+ parent_module.const_set(
107
+ "#{c}#{@db.object_id.to_s.gsub('-', 'M')}",
108
+ Class.new(parent_module.const_get(c)) do
109
+ self.dataset = s.db["#{table_prefix}#{key}".to_sym]
110
+ self.unit = s.unit
111
+ end)
112
+ end
70
113
 
71
- @models[k] ||=
72
- Flor.const_set(
73
- "#{c}#{@db.object_id.to_s.gsub('-', 'M')}",
74
- Class.new(Flor.const_get(c)) do
75
- self.dataset = s.db["flor_#{k}".to_sym]
76
- end)
77
- end
114
+ Flor::Scheduler.send(:define_method, key) do
115
+
116
+ @storage.send(key)
78
117
  end
79
118
  end
80
119
 
81
- class Scheduler
120
+ MODELS.each do |k|
82
121
 
83
- MODELS.each do |k|
84
-
85
- define_method(k) { @storage.send(k) }
86
- end
122
+ add_model(k)
87
123
  end
88
124
  end
89
125
 
@@ -20,6 +20,9 @@ module Flor
20
20
 
21
21
  def nodes; data['nodes']; end
22
22
  def zero_node; nodes['0']; end
23
+ def closing_messages; data['closing_messages']; end
24
+
25
+ def execution(reload=false); self; end
23
26
 
24
27
  def tags
25
28
 
@@ -45,14 +48,22 @@ module Flor
45
48
 
46
49
  tree = nodes['0']['tree']
47
50
 
48
- nodes.each do |nid, n|
49
- next if nid == '0'
50
- t = n['tree']; next unless t
51
- end
51
+ #nodes.each do |nid, n|
52
+ # next if nid == '0'
53
+ # t = n['tree']; next unless t
54
+ #end
55
+ #
56
+ # FIXME
52
57
 
53
58
  tree
54
59
  end
55
60
 
61
+ def lookup_tree(nid)
62
+
63
+ Flor::Node.new(self.data, nodes[nid], nil)
64
+ .lookup_tree(nid)
65
+ end
66
+
56
67
  def zero_variables
57
68
 
58
69
  zero_node['vars']
@@ -12,6 +12,7 @@ module Flor
12
12
  # String :type, null: false # task, tasked, tag, var
13
13
  # String :name, null: false # task name, tasked name, tag name, var name
14
14
  # String :value
15
+ # File :content
15
16
  # String :ctime, null: false
16
17
  #
17
18
  # # no :status, no :mtime
@@ -26,6 +27,16 @@ module Flor
26
27
  # #unique [ :exid, :type, :name, :value ]
27
28
  # # we don't care, pointers are cleaned anyway when the flow dies
28
29
  #end
30
+
31
+ # If the pointer is a "var" pointer, returns the full value
32
+ # for the variable, as fund in the execution's node "0".
33
+ #
34
+ def full_value
35
+
36
+ return nil unless type == 'var'
37
+
38
+ node['vars'][name]
39
+ end
29
40
  end
30
41
  end
31
42
 
@@ -111,11 +111,6 @@ module Flor
111
111
  @ganger.shutdown
112
112
  end
113
113
 
114
- def hook(*args, &block)
115
-
116
- @hooker.add(*args, &block)
117
- end
118
-
119
114
  def on_start_exc(e)
120
115
 
121
116
  io = StringIO.new
@@ -182,13 +177,9 @@ module Flor
182
177
 
183
178
  source, domain, flow_name =
184
179
  if df = Flor.split_flow_name(source_or_path)
185
- [ source_or_path,
186
- opts[:domain] || df[0],
187
- df[1] ]
180
+ [ source_or_path, opts[:domain] || df[0], df[1] ]
188
181
  else
189
- [ source_or_path,
190
- opts[:domain] || @conf['domain'] || 'domain0',
191
- nil ]
182
+ [ source_or_path, opts[:domain] || @conf['domain'] || 'domain0', nil ]
192
183
  end
193
184
 
194
185
  fail ArgumentError.new(
@@ -280,6 +271,68 @@ module Flor
280
271
  end
281
272
  alias reapply re_apply
282
273
 
274
+ def add_branches(exid, *as)
275
+
276
+ m = prepare_message('add-branches', [ exid, *as ]).first
277
+
278
+ exe = @storage.executions[exid: m['exid']]
279
+ pnid = m['nid']
280
+ ptree = exe.lookup_tree(pnid)
281
+
282
+ fail ArgumentError.new(
283
+ "parent #{pnid} is a leaf, cannot add branch at #{tnid}"
284
+ ) unless ptree[1].is_a?(Array)
285
+ #
286
+ # not likely to happen, since leaves reply immediately
287
+
288
+ size = ptree[1].size
289
+ tnid = (m['tnid'] ||= Flor.make_child_nid(pnid, size))
290
+
291
+ cid = Flor.child_id(tnid)
292
+
293
+ tide, tcid = nil
294
+ (0..size - 1).reverse_each do |i|
295
+ tcid = Flor.make_child_nid(pnid, i)
296
+ next unless exe.nodes[tcid]
297
+ tide = i; break
298
+ end
299
+
300
+ fail ArgumentError.new(
301
+ "target #{tnid} too low, execution has already reached #{tcid}"
302
+ ) if tide && cid < tide
303
+
304
+ fail ArgumentError.new(
305
+ "target #{tnid} is off by #{cid - size}, " +
306
+ "node #{pnid} has #{size} branch#{size == 1 ? '' : 'es'}"
307
+ ) if cid > size
308
+
309
+ queue(m)
310
+ end
311
+ alias add_branch add_branches
312
+
313
+ def add_iterations(exid, *as)
314
+
315
+ m = prepare_message('add-iterations', [ exid, *as ]).first
316
+
317
+ exe = @storage.executions[exid: m['exid']]
318
+ nid = m['nid']
319
+
320
+ fail ArgumentError.new(
321
+ "cannot add iteration to missing execution #{m['exid'].inspect}"
322
+ ) unless exe
323
+
324
+ fail ArgumentError.new(
325
+ "missing nid: or pnid:"
326
+ ) unless nid
327
+
328
+ fail ArgumentError.new(
329
+ "cannot add iteration to missing node #{nid.inspect}"
330
+ ) unless exe.lookup_tree(nid)
331
+
332
+ queue(m)
333
+ end
334
+ alias add_iteration add_iterations
335
+
283
336
  def schedule(message)
284
337
 
285
338
  @storage.put_timer(message)
@@ -367,20 +420,6 @@ module Flor
367
420
  puts on_start_exc(ex)
368
421
  end
369
422
 
370
- def prepare_re_apply_messages(msg, opts)
371
-
372
- fail ArgumentError.new("missing 'payload' to re_apply") \
373
- unless msg['payload']
374
-
375
- t = Flor.parse(opts[:tree], 're_apply', {})
376
-
377
- [ { 'point' => 'execute',
378
- 'exid' => msg['exid'], 'nid' => msg['nid'],
379
- 'from' => 'parent',
380
- 'tree' => t,
381
- 'payload' => msg['payload'] } ]
382
- end
383
-
384
423
  def prepare_message(point, args)
385
424
 
386
425
  h =
@@ -394,11 +433,6 @@ module Flor
394
433
  msg = { 'point' => point }
395
434
  opts = {}
396
435
 
397
- if point == 'kill'
398
- msg['point'] = 'cancel'
399
- msg['flavour'] = 'kill'
400
- end
401
-
402
436
  h.each do |k, v|
403
437
  if %w[ exid name nid payload on_receive_last ].include?(k)
404
438
  msg[k] = v
@@ -407,7 +441,30 @@ module Flor
407
441
  end
408
442
  end
409
443
 
444
+ if point == 'kill'
445
+
446
+ msg['point'] = 'cancel'
447
+ msg['flavour'] = 'kill'
448
+
449
+ elsif point == 'add-branches'
450
+
451
+ msg['point'] = 'add'
452
+ msg['trees'] = prepare_trees(opts)
453
+
454
+ msg['tnid'] = tnid =
455
+ opts.delete(:tnid) || msg.delete('nid')
456
+ msg['nid'] =
457
+ msg.delete('nid') || opts.delete(:pnid) || Flor.parent_nid(tnid)
458
+
459
+ elsif point == 'add-iterations'
460
+
461
+ msg['point'] = 'add'
462
+ msg['elements'] = prepare_elements(opts)
463
+ msg['nid'] = msg.delete('nid') || opts.delete(:pnid)
464
+ end
465
+
410
466
  if opts[:re_apply]
467
+
411
468
  msg['on_receive_last'] = prepare_re_apply_messages(msg, opts)
412
469
  end
413
470
 
@@ -419,6 +476,45 @@ module Flor
419
476
  [ msg, opts ]
420
477
  end
421
478
 
479
+ def prepare_trees(opts)
480
+
481
+ fname = Flor.caller_fname
482
+
483
+ ts = (opts[:trees] || [ opts[:tree] ].compact)
484
+ .collect { |t| Flor.parse(t, fname, {}) }
485
+
486
+ fail ArgumentError.new('missing trees: or tree:') if ts.empty?
487
+
488
+ ts
489
+ end
490
+
491
+ def prepare_elements(opts)
492
+
493
+ elts =
494
+ opts[:elements] || opts[:elts] ||
495
+ opts[:element] || opts[:elt]
496
+
497
+ fail ArgumentError.new('missing elements: or element:') unless elts
498
+
499
+ elts = [ elts ] unless elts.is_a?(Array)
500
+
501
+ elts
502
+ end
503
+
504
+ def prepare_re_apply_messages(msg, opts)
505
+
506
+ fail ArgumentError.new("missing 'payload' to re_apply") \
507
+ unless msg['payload']
508
+
509
+ t = Flor.parse(opts[:tree], Flor.caller_fname, {})
510
+
511
+ [ { 'point' => 'execute',
512
+ 'exid' => msg['exid'], 'nid' => msg['nid'],
513
+ 'from' => 'parent',
514
+ 'tree' => t,
515
+ 'payload' => msg['payload'] } ]
516
+ end
517
+
422
518
  def make_idle_message
423
519
 
424
520
  m = {}