flor 1.2.2 → 1.5.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -0
- data/lib/flor/core/node.rb +2 -2
- data/lib/flor/core/procedure.rb +47 -4
- data/lib/flor/log.rb +1 -1
- data/lib/flor/parser.rb +2 -0
- data/lib/flor/pcore/_apply.rb +1 -1
- data/lib/flor/pcore/on.rb +2 -1
- data/lib/flor/pcore/on_receive.rb +102 -0
- data/lib/flor/punit/concurrence.rb +1 -1
- data/lib/flor/tools/flotojson.rb +90 -0
- data/lib/flor/unit/logger.rb +2 -1
- data/lib/flor/unit/models/execution.rb +63 -14
- data/lib/flor/unit/scheduler.rb +30 -28
- data/lib/flor/unit/storage.rb +116 -36
- data/lib/flor.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 352d4347077550a9e577689e8b1f11ad90b7efb0d6fa14e99a228b634852c55f
|
4
|
+
data.tar.gz: 81015d54353ff68b48108e09fdfc8933cae2b20ed48ccba1679bebc1b67258da
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c322beec0f868fbf72c79678227cbf2a2fea34611fe340b1fdd680a7d6b1f5a09246af1a78f6923977a061772ef22fc8d20d2d13a0bad2145991f296b4cfd143
|
7
|
+
data.tar.gz: 3c3e2ce6a88acbaeeab0bb9d89f8c22e5dfd8fb1a81491f0d54983d21d692e3cd93262c842ed8dbc00e021b2fee1d5f3e3e791d8af72bfc6667c472d712d3541
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,28 @@
|
|
2
2
|
# CHANGELOG.md
|
3
3
|
|
4
4
|
|
5
|
+
## flor 1.5.0 released 2021-11-24
|
6
|
+
|
7
|
+
* Add storage callbacks `on(:pointers, :any) { do_that }`
|
8
|
+
* Add `on_receive` (and `on receive`)
|
9
|
+
|
10
|
+
|
11
|
+
## flor 1.4.0 released 2021-11-10
|
12
|
+
|
13
|
+
* Add :tree to Execution#to_h
|
14
|
+
* Scaffold bin/flotojson
|
15
|
+
|
16
|
+
|
17
|
+
## flor 1.3.1 released 2021-04-19
|
18
|
+
|
19
|
+
* Fix flor_pointers var deletion mechanism (type = ' var ')
|
20
|
+
|
21
|
+
|
22
|
+
## flor 1.3.0 released 2021-04-13
|
23
|
+
|
24
|
+
* Insert a row flor_pointers for 'failure'
|
25
|
+
|
26
|
+
|
5
27
|
## flor 1.2.2 released 2021-03-29
|
6
28
|
|
7
29
|
* Include data in flor_pointers
|
data/lib/flor/core/node.rb
CHANGED
@@ -88,7 +88,7 @@ class Flor::Node
|
|
88
88
|
def domain; Flor.domain(@execution['exid']); end
|
89
89
|
|
90
90
|
def point; @message['point']; end
|
91
|
-
def from; @message['from']; end
|
91
|
+
def from; @from || @message['from']; end
|
92
92
|
|
93
93
|
def cnodes; @node['cnodes']; end
|
94
94
|
def cnodes_any?; cnodes && cnodes.any?; end
|
@@ -149,7 +149,7 @@ class Flor::Node
|
|
149
149
|
tree = lookup_tree(Flor.parent_nid(nid))
|
150
150
|
return tree[1][cid] if tree
|
151
151
|
|
152
|
-
#tree = lookup_tree(Flor.parent_nid(nid, true))
|
152
|
+
#tree = lookup_tree(Flor.parent_nid(nid, remove_subnid=true))
|
153
153
|
#return tree[1][cid] if tree
|
154
154
|
#
|
155
155
|
# might become necessary at some point
|
data/lib/flor/core/procedure.rb
CHANGED
@@ -5,7 +5,7 @@ class Flor::Procedure < Flor::Node
|
|
5
5
|
# "Returning vars" variables to pass back to pass upon reply.
|
6
6
|
# In the 'receive' messages, it's a hash under the key 'rvars'.
|
7
7
|
#
|
8
|
-
RVARS = %w[ idx ]
|
8
|
+
RVARS = %w[ idx ].freeze
|
9
9
|
|
10
10
|
# Attributes that when given alone are turned to "true" attributes.
|
11
11
|
#
|
@@ -13,7 +13,7 @@ class Flor::Procedure < Flor::Node
|
|
13
13
|
#
|
14
14
|
# The transformation occurs in Flor::Pro::Att ("_att").
|
15
15
|
#
|
16
|
-
TRUE_ATTS = %w[ flank off disabled ]
|
16
|
+
TRUE_ATTS = %w[ flank off disabled ].freeze
|
17
17
|
|
18
18
|
class << self
|
19
19
|
|
@@ -381,8 +381,17 @@ class Flor::Procedure < Flor::Node
|
|
381
381
|
|
382
382
|
receive_when_ended
|
383
383
|
|
384
|
+
elsif should_apply_on_receive?
|
385
|
+
|
386
|
+
apply_on_receive
|
387
|
+
|
384
388
|
else
|
385
389
|
|
390
|
+
orn = @node['on_receive_nid']
|
391
|
+
@from = orn[1] if orn && orn[0] == from
|
392
|
+
#
|
393
|
+
# in order to move on to the next child...
|
394
|
+
|
386
395
|
receive
|
387
396
|
end
|
388
397
|
end
|
@@ -550,6 +559,8 @@ class Flor::Procedure < Flor::Node
|
|
550
559
|
wrap_reply
|
551
560
|
end
|
552
561
|
|
562
|
+
IF_UNLESS = %w[ _if _unless ].freeze
|
563
|
+
|
553
564
|
# Grab on_error proc from incoming payload and stores it into parent node.
|
554
565
|
#
|
555
566
|
# Has no effect if there is no parent node.
|
@@ -562,7 +573,7 @@ class Flor::Procedure < Flor::Node
|
|
562
573
|
@node; loop do
|
563
574
|
pnode = parent_node(pnode)
|
564
575
|
return unless pnode
|
565
|
-
break unless
|
576
|
+
break unless IF_UNLESS.include?(pnode['heap'])
|
566
577
|
end
|
567
578
|
|
568
579
|
flavour = "on_#{key}"
|
@@ -598,6 +609,8 @@ class Flor::Procedure < Flor::Node
|
|
598
609
|
wrap('point' => 'entered', 'nid' => nid, 'tags' => ret)
|
599
610
|
end
|
600
611
|
|
612
|
+
WRAP_KEYS = %w[ error cancel timeout ].freeze
|
613
|
+
|
601
614
|
def wrap(h={})
|
602
615
|
|
603
616
|
m = {}
|
@@ -642,7 +655,7 @@ class Flor::Procedure < Flor::Node
|
|
642
655
|
# was considering passing the whole vars back (as 'varz'), but
|
643
656
|
# it got in the way... and it might be heavy
|
644
657
|
|
645
|
-
|
658
|
+
WRAP_KEYS
|
646
659
|
.each { |k|
|
647
660
|
co = @node["child_on_#{k}"]
|
648
661
|
next unless co
|
@@ -978,6 +991,36 @@ class Flor::Procedure < Flor::Node
|
|
978
991
|
|
979
992
|
[]
|
980
993
|
end
|
994
|
+
|
995
|
+
def should_apply_on_receive?
|
996
|
+
|
997
|
+
return false if @message['from_on'] == 'receive'
|
998
|
+
#
|
999
|
+
# no, since the message comes from an on_receive...
|
1000
|
+
# how about nested on_receives?
|
1001
|
+
|
1002
|
+
orc = @node['on_receive']
|
1003
|
+
return false if orc.nil? || orc.empty?
|
1004
|
+
|
1005
|
+
orn = @node['on_receive_nid']
|
1006
|
+
return false if orn && orn[0] == from
|
1007
|
+
|
1008
|
+
true
|
1009
|
+
end
|
1010
|
+
|
1011
|
+
def apply_on_receive
|
1012
|
+
|
1013
|
+
determine_fcid_and_ncid
|
1014
|
+
|
1015
|
+
args = [
|
1016
|
+
[ 'msg', @message ],
|
1017
|
+
[ 'fcid', @fcid ] ]
|
1018
|
+
|
1019
|
+
ms = apply(@node['on_receive'][0][1], args, tree[2])
|
1020
|
+
@node['on_receive_nid'] = [ ms[0]['nid'], from ]
|
1021
|
+
|
1022
|
+
ms
|
1023
|
+
end
|
981
1024
|
end
|
982
1025
|
|
983
1026
|
|
data/lib/flor/log.rb
CHANGED
@@ -343,7 +343,7 @@ module Flor
|
|
343
343
|
o.puts(tree_to_s(node.lookup_tree(nid), nid, out: o)) if node
|
344
344
|
|
345
345
|
o.puts "#{_c.dg}node:#{_c.yl}"
|
346
|
-
o.puts YAML.dump(n.merge('tree' => '(above)'))
|
346
|
+
o.puts n ? YAML.dump(n.merge('tree' => '(above)')) : 'nil'
|
347
347
|
|
348
348
|
o.puts "#{_c.dg}nodes:#{_c.yl}"
|
349
349
|
o.puts nods_to_s(executor, m, opts)
|
data/lib/flor/parser.rb
CHANGED
data/lib/flor/pcore/_apply.rb
CHANGED
@@ -99,7 +99,7 @@ class Flor::Pro::UnderscoreApply < Flor::Procedure
|
|
99
99
|
|
100
100
|
params.each do |param_key, param_tree|
|
101
101
|
next if param_tree[0] == '_ref'
|
102
|
-
arg_i = args.index { |arg_key,
|
102
|
+
arg_i = args.index { |arg_key, _| arg_key == param_key }
|
103
103
|
next unless arg_i
|
104
104
|
arg_key, arg_val = args.delete_at(arg_i)
|
105
105
|
seen << arg_key
|
data/lib/flor/pcore/on.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
|
3
4
|
class Flor::Pro::On < Flor::Macro
|
4
5
|
#
|
5
6
|
# Catches signals or errors.
|
@@ -132,7 +133,7 @@ class Flor::Pro::On < Flor::Macro
|
|
132
133
|
|
133
134
|
protected
|
134
135
|
|
135
|
-
CATCHES = %w[ error cancel timeout ].freeze
|
136
|
+
CATCHES = %w[ error cancel timeout receive ].freeze
|
136
137
|
|
137
138
|
def find_catch
|
138
139
|
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
|
4
|
+
class Flor::Pro::OnReceive < Flor::Procedure
|
5
|
+
#
|
6
|
+
# Binds a function to the parent node, the function will be called each time
|
7
|
+
# the parent node "receives".
|
8
|
+
#
|
9
|
+
# ```
|
10
|
+
# set l []
|
11
|
+
# sequence
|
12
|
+
# on_receive (def msg \ push l 'a')
|
13
|
+
# push l 0
|
14
|
+
# push l 1
|
15
|
+
# push l 2
|
16
|
+
# ```
|
17
|
+
# will result in the variable `l` holding `[ 0, 'a', 1, 'a', 2, 'a' ]`.
|
18
|
+
#
|
19
|
+
# ```
|
20
|
+
# set l []
|
21
|
+
# sequence
|
22
|
+
# push l 0
|
23
|
+
# on_receive (def msg \ push l 'a')
|
24
|
+
# push l 1
|
25
|
+
# push l 2
|
26
|
+
# ```
|
27
|
+
# will result in the variable `l` holding `[ 0, 1, 'a', 2, 'a' ]`.
|
28
|
+
#
|
29
|
+
# It's meant to play well with a cursor:
|
30
|
+
# ```
|
31
|
+
# set l []
|
32
|
+
# cursor
|
33
|
+
# on_receive (def \ break _ if l[-1] == 1)
|
34
|
+
# push l 0
|
35
|
+
# push l 1
|
36
|
+
# push l 2
|
37
|
+
# push l 'z'
|
38
|
+
# ```
|
39
|
+
# will result in the variable `l` holding `[ 0, 1, 'z' ]`.
|
40
|
+
#
|
41
|
+
#
|
42
|
+
# ## arguments to the on_receive function
|
43
|
+
#
|
44
|
+
# `msg` and `fcid` (from child id) are passed to the function
|
45
|
+
# ```
|
46
|
+
# set l []
|
47
|
+
# cursor
|
48
|
+
# on_receive (def msg, fcid \ push l [ msg.from, fcid ])
|
49
|
+
# push l 0
|
50
|
+
# push l 1
|
51
|
+
# push l 2
|
52
|
+
# ```
|
53
|
+
# will result in the variable `l` holding
|
54
|
+
# `[ 0, [ '0_1_1', 1 ], 1, [ '0_1_2', 2 ], 2, [ '0_1_3', 3 ] ]`.
|
55
|
+
#
|
56
|
+
#
|
57
|
+
# ## on_receive and on receive
|
58
|
+
#
|
59
|
+
# A "lighter" notation is available (it's translated automatically to a
|
60
|
+
# `on_receive`):
|
61
|
+
# ```
|
62
|
+
# set l []
|
63
|
+
# cursor
|
64
|
+
# on receive
|
65
|
+
# push l $msg.from
|
66
|
+
# break _ if l.-1 == 1
|
67
|
+
# push l 0
|
68
|
+
# push l 1
|
69
|
+
# push l 2
|
70
|
+
# ```
|
71
|
+
#
|
72
|
+
# Please note the `$msg` variable made available to the `on receive` block.
|
73
|
+
#
|
74
|
+
#
|
75
|
+
# ## concurrence and on_receive
|
76
|
+
#
|
77
|
+
# Please not that `concurrence` has its own `on_receive` with a slightly
|
78
|
+
# different behaviour.
|
79
|
+
|
80
|
+
name 'on_receive'
|
81
|
+
|
82
|
+
def pre_execute
|
83
|
+
|
84
|
+
unatt_unkeyed_children
|
85
|
+
|
86
|
+
@node['rets'] = []
|
87
|
+
end
|
88
|
+
|
89
|
+
def receive_last
|
90
|
+
|
91
|
+
prc = @node['rets'].find { |r| Flor.is_func_tree?(r) }
|
92
|
+
|
93
|
+
store_on(:receive, prc)
|
94
|
+
|
95
|
+
ms = super
|
96
|
+
|
97
|
+
ms.first['from_on'] = 'receive'
|
98
|
+
|
99
|
+
ms
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# flotojson.rb
|
4
|
+
|
5
|
+
require 'flor'
|
6
|
+
|
7
|
+
FLAGS_WITH_VALUE = []
|
8
|
+
|
9
|
+
flags = {}
|
10
|
+
files = []
|
11
|
+
|
12
|
+
if (ARGV & [ '-h', '--help']).any?
|
13
|
+
puts
|
14
|
+
puts "bin/flotojson [flags] filename"
|
15
|
+
puts
|
16
|
+
puts " turns a flor .flo process definition to its tree representation"
|
17
|
+
puts
|
18
|
+
puts " flags:"
|
19
|
+
puts " --pp pretty prints instead of dumping as JSON"
|
20
|
+
puts
|
21
|
+
puts " --pj"
|
22
|
+
puts " --jp pretty prints the JSON output"
|
23
|
+
puts
|
24
|
+
puts " -y"
|
25
|
+
puts " -yaml dumps as YAML"
|
26
|
+
puts
|
27
|
+
puts " -h"
|
28
|
+
puts " --help prints this help message"
|
29
|
+
puts
|
30
|
+
exit 0
|
31
|
+
end
|
32
|
+
|
33
|
+
args = ARGV.dup
|
34
|
+
|
35
|
+
loop do
|
36
|
+
|
37
|
+
a = args.shift; break unless a
|
38
|
+
|
39
|
+
if a.size > 1 && a[0, 1] == '-'
|
40
|
+
flags[a] = FLAGS_WITH_VALUE.include?(a) ? a.shift : true
|
41
|
+
else
|
42
|
+
files << a
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
#STDERR.puts flags.inspect
|
47
|
+
#STDERR.puts files.inspect
|
48
|
+
|
49
|
+
# t =
|
50
|
+
# tree.is_a?(String) ?
|
51
|
+
# Flor.parse(tree, opts[:fname] || opts[:path], opts) :
|
52
|
+
# tree
|
53
|
+
#
|
54
|
+
# unless t
|
55
|
+
#
|
56
|
+
# #h = opts.merge(prune: false, rewrite: false, debug: 0)
|
57
|
+
# #Raabro.pp(Flor.parse(tree, h[:fname], h))
|
58
|
+
# # TODO re-parse and indicate what went wrong...
|
59
|
+
#
|
60
|
+
# fail ArgumentError.new(
|
61
|
+
# "flow parsing failed: " + tree.inspect[0, 35] + '...')
|
62
|
+
# end
|
63
|
+
|
64
|
+
fname = files.first
|
65
|
+
|
66
|
+
content =
|
67
|
+
if fname
|
68
|
+
abort("File #{fname.inspect} not found") unless File.exist?(fname)
|
69
|
+
File.read(fname)
|
70
|
+
else
|
71
|
+
STDIN.read
|
72
|
+
end
|
73
|
+
|
74
|
+
tree = Flor.parse(content, fname, {})
|
75
|
+
|
76
|
+
if flags['--pp']
|
77
|
+
pp tree
|
78
|
+
elsif flags['--jp'] || flags['--pj']
|
79
|
+
puts(
|
80
|
+
JSON.pretty_generate(tree)
|
81
|
+
.gsub(/\[\s+/, '[ ')
|
82
|
+
.gsub(/\]\s+/, ']')
|
83
|
+
.gsub(/,\s+(\d+)\s+\]/, ', \1]')
|
84
|
+
)
|
85
|
+
elsif flags['-y'] || flags['--yaml']
|
86
|
+
puts YAML.dump(tree)
|
87
|
+
else
|
88
|
+
puts JSON.dump(tree)
|
89
|
+
end
|
90
|
+
|
data/lib/flor/unit/logger.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
|
3
4
|
module Flor
|
4
5
|
|
5
6
|
# TODO ::Logger has a formatting callback
|
@@ -11,7 +12,7 @@ module Flor
|
|
11
12
|
|
12
13
|
# NB: logger configuration entries start with "log_"
|
13
14
|
|
14
|
-
LEVELS_I = %w[ DEBUG INFO WARN ERROR FATAL UNKNOWN ]
|
15
|
+
LEVELS_I = %w[ DEBUG INFO WARN ERROR FATAL UNKNOWN ].freeze
|
15
16
|
|
16
17
|
def initialize(unit)
|
17
18
|
|
@@ -20,7 +20,29 @@ module Flor
|
|
20
20
|
#end
|
21
21
|
|
22
22
|
def nodes; data['nodes']; end
|
23
|
+
|
23
24
|
def zero_node; nodes['0']; end
|
25
|
+
|
26
|
+
# Returns the nids, the lower in the tree, the earlier in the returned
|
27
|
+
# array.
|
28
|
+
#
|
29
|
+
def sorted_nids
|
30
|
+
|
31
|
+
nodes.keys
|
32
|
+
.inject([]) { |a, nid|
|
33
|
+
l = nid.split('_').length
|
34
|
+
(a[l] ||= []) << nid
|
35
|
+
a }
|
36
|
+
.compact
|
37
|
+
.collect(&:sort)
|
38
|
+
.flatten(1)
|
39
|
+
end
|
40
|
+
|
41
|
+
def lowest_node
|
42
|
+
|
43
|
+
nodes[sorted_nids.first]
|
44
|
+
end
|
45
|
+
|
24
46
|
def closing_messages; data['closing_messages']; end
|
25
47
|
|
26
48
|
def execution(reload=false); self; end
|
@@ -47,14 +69,16 @@ module Flor
|
|
47
69
|
|
48
70
|
def full_tree
|
49
71
|
|
50
|
-
|
72
|
+
nids = sorted_nids
|
73
|
+
nid0 = nids.shift
|
51
74
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
75
|
+
return nil unless nid0
|
76
|
+
|
77
|
+
tree = Flor.dup(nodes[nid0]['tree'])
|
78
|
+
|
79
|
+
nids.each { |nid|
|
80
|
+
next unless nid.split('_', 2).first == nid0
|
81
|
+
replace_sub_tree(tree, nid, nodes[nid]['tree']) }
|
58
82
|
|
59
83
|
tree
|
60
84
|
end
|
@@ -80,21 +104,22 @@ module Flor
|
|
80
104
|
cs = m[:counts] = {}
|
81
105
|
is = m[:nids] = { tasks: [], failures: [] }
|
82
106
|
|
83
|
-
|
84
|
-
|
107
|
+
cs[:failures] = 0
|
108
|
+
cs[:tasks] = 0
|
109
|
+
cs[:nodes] = nodes.count
|
110
|
+
#
|
85
111
|
nodes.each do |k, v|
|
86
112
|
if v['task']
|
87
|
-
|
113
|
+
cs[:tasks] += 1
|
88
114
|
is[:tasks] << k
|
89
115
|
end
|
90
116
|
if v['failure']
|
91
|
-
|
117
|
+
cs[:failures] += 1
|
92
118
|
is[:failures] << k
|
93
119
|
end
|
94
120
|
end
|
95
|
-
|
96
|
-
|
97
|
-
cs[:tasks] = ts
|
121
|
+
|
122
|
+
h[:tree] = full_tree
|
98
123
|
|
99
124
|
h
|
100
125
|
end
|
@@ -149,6 +174,30 @@ module Flor
|
|
149
174
|
lookup_node(query, opts)['nid']
|
150
175
|
end
|
151
176
|
|
177
|
+
protected
|
178
|
+
|
179
|
+
def replace_sub_tree(tree, nid, t)
|
180
|
+
|
181
|
+
return unless t
|
182
|
+
return if nid.index('-') # stay vanilla
|
183
|
+
|
184
|
+
snid = nid.split('_').collect(&:to_i)[1..-1]
|
185
|
+
a = get_child_array(tree, snid)
|
186
|
+
|
187
|
+
return unless a # shouldn't we fail?
|
188
|
+
|
189
|
+
a[snid.first] = Flor.dup(t)
|
190
|
+
end
|
191
|
+
|
192
|
+
def get_child_array(tree, snid)
|
193
|
+
|
194
|
+
return nil if tree.nil?
|
195
|
+
return nil if snid.length < 1
|
196
|
+
return nil unless tree[1].is_a?(Array)
|
197
|
+
return tree[1] if snid.length == 1
|
198
|
+
n = snid.shift; get_child_array(tree[1][n], snid)
|
199
|
+
end
|
200
|
+
|
152
201
|
class << self
|
153
202
|
|
154
203
|
def by_status(s)
|
data/lib/flor/unit/scheduler.rb
CHANGED
@@ -113,27 +113,6 @@ module Flor
|
|
113
113
|
@ganger.shutdown
|
114
114
|
end
|
115
115
|
|
116
|
-
def on_start_exc(e)
|
117
|
-
|
118
|
-
io = StringIO.new
|
119
|
-
|
120
|
-
head, kind =
|
121
|
-
e.is_a?(StandardError) ? [ '=sch', 'error' ] : [ '!sch', 'exception' ]
|
122
|
-
thr = Thread.current
|
123
|
-
|
124
|
-
t = head[0, 2] + Time.now.to_f.to_s.split('.').last
|
125
|
-
io.puts ' /' + t + ' ' + head * 17
|
126
|
-
io.puts " |#{t} + in #{self.class}#start"
|
127
|
-
io.puts " |#{t} db: #{@storage.db.class} #{@storage.db.object_id}"
|
128
|
-
io.puts " |#{t} thread: t#{thr.object_id} #{thr.inspect}"
|
129
|
-
io.puts " |#{t} #{kind}: #{e.inspect}"
|
130
|
-
io.puts " |#{t} backtrace:"
|
131
|
-
e.backtrace.each { |l| io.puts "|#{t} #{l}" }
|
132
|
-
io.puts ' \\' + t + ' ' + (head * 17) + ' .'
|
133
|
-
|
134
|
-
io.string
|
135
|
-
end
|
136
|
-
|
137
116
|
def start
|
138
117
|
|
139
118
|
# TODO heartbeat, every x minutes, when idle, log something
|
@@ -242,18 +221,18 @@ module Flor
|
|
242
221
|
end
|
243
222
|
end
|
244
223
|
|
224
|
+
RETURN_KEYS = %w[ exid nid payload tasker cause ].freeze
|
225
|
+
|
245
226
|
def return(message)
|
246
227
|
|
247
|
-
|
228
|
+
queue(
|
248
229
|
if message['point'] == 'failed'
|
249
230
|
message
|
250
231
|
else
|
251
232
|
message
|
252
|
-
.select { |k, _|
|
233
|
+
.select { |k, _| RETURN_KEYS.include?(k) }
|
253
234
|
.merge!('point' => 'return')
|
254
|
-
end
|
255
|
-
|
256
|
-
queue(m)
|
235
|
+
end)
|
257
236
|
|
258
237
|
nil
|
259
238
|
end
|
@@ -432,7 +411,7 @@ module Flor
|
|
432
411
|
ex ? ex.execution : nil
|
433
412
|
end
|
434
413
|
|
435
|
-
DUMP_KEYS = %w[ timestamp executions timers traps pointers ]
|
414
|
+
DUMP_KEYS = %w[ timestamp executions timers traps pointers ].freeze
|
436
415
|
|
437
416
|
# Dumps all or some of the executions to a JSON string.
|
438
417
|
# See Scheduler#load for importing.
|
@@ -557,6 +536,27 @@ module Flor
|
|
557
536
|
|
558
537
|
protected
|
559
538
|
|
539
|
+
def on_start_exc(e)
|
540
|
+
|
541
|
+
io = StringIO.new
|
542
|
+
|
543
|
+
head, kind =
|
544
|
+
e.is_a?(StandardError) ? [ '=sch', 'error' ] : [ '!sch', 'exception' ]
|
545
|
+
thr = Thread.current
|
546
|
+
|
547
|
+
t = head[0, 2] + Time.now.to_f.to_s.split('.').last
|
548
|
+
io.puts ' /' + t + ' ' + head * 17
|
549
|
+
io.puts " |#{t} + in #{self.class}#start"
|
550
|
+
io.puts " |#{t} db: #{@storage.db.class} #{@storage.db.object_id}"
|
551
|
+
io.puts " |#{t} thread: t#{thr.object_id} #{thr.inspect}"
|
552
|
+
io.puts " |#{t} #{kind}: #{e.inspect}"
|
553
|
+
io.puts " |#{t} backtrace:"
|
554
|
+
e.backtrace.each { |l| io.puts "|#{t} #{l}" }
|
555
|
+
io.puts ' \\' + t + ' ' + (head * 17) + ' .'
|
556
|
+
|
557
|
+
io.string
|
558
|
+
end
|
559
|
+
|
560
560
|
def extract_dump_and_load_filters(opts)
|
561
561
|
|
562
562
|
o = lambda { |k| v = opts[k] || opts["#{k}s".to_sym]; v ? Array(v) : nil }
|
@@ -598,6 +598,8 @@ module Flor
|
|
598
598
|
puts(on_start_exc(ex))
|
599
599
|
end
|
600
600
|
|
601
|
+
PREP_KEYS = %w[ exid name nid payload on_receive_last ].freeze
|
602
|
+
|
601
603
|
def prepare_message(point, args)
|
602
604
|
|
603
605
|
h = args
|
@@ -612,7 +614,7 @@ module Flor
|
|
612
614
|
opts = {}
|
613
615
|
|
614
616
|
h.each do |k, v|
|
615
|
-
if
|
617
|
+
if PREP_KEYS.include?(k)
|
616
618
|
msg[k] = v
|
617
619
|
else
|
618
620
|
opts[k.to_sym] = v
|
data/lib/flor/unit/storage.rb
CHANGED
@@ -16,7 +16,7 @@ module Flor
|
|
16
16
|
:content
|
17
17
|
].freeze
|
18
18
|
|
19
|
-
attr_reader :unit, :db, :models
|
19
|
+
attr_reader :unit, :db, :models, :callbacks
|
20
20
|
|
21
21
|
attr_reader :mutex
|
22
22
|
# might be useful for some implementations
|
@@ -31,6 +31,8 @@ module Flor
|
|
31
31
|
@archive = @unit.conf['sto_archive']
|
32
32
|
@mutex = @unit.conf['sto_sync'] ? Mutex.new : nil
|
33
33
|
|
34
|
+
@callbacks = {}
|
35
|
+
|
34
36
|
connect
|
35
37
|
end
|
36
38
|
|
@@ -191,6 +193,8 @@ module Flor
|
|
191
193
|
mtime: now,
|
192
194
|
munit: u)
|
193
195
|
|
196
|
+
callback(:executions, :update, id)
|
197
|
+
|
194
198
|
else
|
195
199
|
|
196
200
|
exe['id'] =
|
@@ -205,6 +209,8 @@ module Flor
|
|
205
209
|
cunit: u,
|
206
210
|
munit: u)
|
207
211
|
.to_i
|
212
|
+
|
213
|
+
callback(:executions, :insert, exe['id'])
|
208
214
|
end
|
209
215
|
|
210
216
|
remove_nodes(exe, status, now)
|
@@ -220,6 +226,9 @@ module Flor
|
|
220
226
|
raise err
|
221
227
|
end
|
222
228
|
|
229
|
+
CRECON_STATUSES = %w[ created consumed ].freeze
|
230
|
+
RESCON_STATUSES = %w[ reserved consumed ].freeze
|
231
|
+
|
223
232
|
def load_messages(exe_count)
|
224
233
|
|
225
234
|
exe_count += 2
|
@@ -230,12 +239,12 @@ module Flor
|
|
230
239
|
_exids_being_processed =
|
231
240
|
@db[:flor_messages]
|
232
241
|
.select(:exid)
|
233
|
-
.exclude(status:
|
242
|
+
.exclude(status: CRECON_STATUSES)
|
234
243
|
_exids =
|
235
244
|
@db[:flor_messages]
|
236
245
|
.select(:exid)
|
237
246
|
.exclude(exid: _exids_being_processed)
|
238
|
-
.exclude(status:
|
247
|
+
.exclude(status: RESCON_STATUSES)
|
239
248
|
.limit(exe_count)
|
240
249
|
@db[:flor_messages]
|
241
250
|
.where(exid: _exids, status: 'created')
|
@@ -318,7 +327,7 @@ module Flor
|
|
318
327
|
[]
|
319
328
|
end
|
320
329
|
|
321
|
-
POINTS_TO_ARCHIVE = %w[ terminated failed ceased ]
|
330
|
+
POINTS_TO_ARCHIVE = %w[ terminated failed ceased ].freeze
|
322
331
|
|
323
332
|
def consume(messages)
|
324
333
|
|
@@ -415,26 +424,29 @@ module Flor
|
|
415
424
|
now = Flor.tstamp
|
416
425
|
u = @unit.identifier
|
417
426
|
|
418
|
-
|
427
|
+
id =
|
428
|
+
synchronize do
|
419
429
|
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
430
|
+
@db[:flor_timers]
|
431
|
+
.insert(
|
432
|
+
domain: Flor.domain(message['exid']),
|
433
|
+
exid: message['exid'],
|
434
|
+
nid: message['nid'],
|
435
|
+
onid: message['onid'] || message['nid'],
|
436
|
+
bnid: message['nid'],
|
437
|
+
type: type,
|
438
|
+
schedule: string,
|
439
|
+
ntime: next_time,
|
440
|
+
content: to_blob(message),
|
441
|
+
count: 0,
|
442
|
+
status: 'active',
|
443
|
+
ctime: now,
|
444
|
+
mtime: now,
|
445
|
+
cunit: u,
|
446
|
+
munit: u)
|
447
|
+
end
|
448
|
+
|
449
|
+
callback(:timers, :insert, id)
|
438
450
|
|
439
451
|
@unit.wake_up
|
440
452
|
|
@@ -499,6 +511,8 @@ module Flor
|
|
499
511
|
munit: u)
|
500
512
|
end
|
501
513
|
|
514
|
+
callback(:traps, :insert, id)
|
515
|
+
|
502
516
|
traps[id]
|
503
517
|
|
504
518
|
rescue => err
|
@@ -545,6 +559,21 @@ module Flor
|
|
545
559
|
nil
|
546
560
|
end
|
547
561
|
|
562
|
+
def on(key, actions=[], &block)
|
563
|
+
|
564
|
+
as =
|
565
|
+
case actions
|
566
|
+
when :any, 'any' then []
|
567
|
+
when Array then actions
|
568
|
+
when Symbol then [ actions ]
|
569
|
+
when String then actions.split(/\s*[;,]\s*/)
|
570
|
+
else []
|
571
|
+
end
|
572
|
+
.collect(&:to_sym)
|
573
|
+
|
574
|
+
(@callbacks[key] ||= []) << [ as, block ]
|
575
|
+
end
|
576
|
+
|
548
577
|
protected
|
549
578
|
|
550
579
|
def migration_table_and_column(opts={})
|
@@ -637,10 +666,11 @@ module Flor
|
|
637
666
|
def reschedule_timer(t)
|
638
667
|
|
639
668
|
w = { id: t.id.to_i, status: 'active', mtime: t.mtime, munit: t.munit }
|
669
|
+
r = nil
|
640
670
|
|
641
671
|
if t.type != 'at' && t.type != 'in'
|
642
672
|
|
643
|
-
@db[:flor_timers]
|
673
|
+
r = @db[:flor_timers]
|
644
674
|
.where(w)
|
645
675
|
.update(
|
646
676
|
count: t.count.to_i + 1,
|
@@ -649,9 +679,11 @@ module Flor
|
|
649
679
|
mtime: Flor.tstamp,
|
650
680
|
munit: @unit.identifier)
|
651
681
|
|
682
|
+
callback(:timers, :update, w, t)
|
683
|
+
|
652
684
|
elsif @archive
|
653
685
|
|
654
|
-
@db[:flor_timers]
|
686
|
+
r = @db[:flor_timers]
|
655
687
|
.where(w)
|
656
688
|
.update(
|
657
689
|
count: t.count.to_i + 1,
|
@@ -659,12 +691,18 @@ module Flor
|
|
659
691
|
mtime: Flor.tstamp,
|
660
692
|
munit: @unit.identifier)
|
661
693
|
|
694
|
+
callback(:timers, :update, w, t)
|
695
|
+
|
662
696
|
else
|
663
697
|
|
664
|
-
@db[:flor_timers]
|
698
|
+
r = @db[:flor_timers]
|
665
699
|
.where(w)
|
666
700
|
.delete
|
701
|
+
|
702
|
+
callback(:timers, :delete, w, t)
|
667
703
|
end
|
704
|
+
|
705
|
+
r
|
668
706
|
end
|
669
707
|
|
670
708
|
def remove_nodes(exe, status, now)
|
@@ -686,6 +724,8 @@ module Flor
|
|
686
724
|
# done in update_pointers
|
687
725
|
end
|
688
726
|
|
727
|
+
FP_TYPES = %w[ var ].freeze
|
728
|
+
|
689
729
|
def update_pointers(exe, status, now)
|
690
730
|
|
691
731
|
# Q Should we archive old pointers?
|
@@ -701,7 +741,7 @@ module Flor
|
|
701
741
|
|
702
742
|
@db[:flor_pointers]
|
703
743
|
.where(exid: exid)
|
704
|
-
.where(Sequel.|({ type:
|
744
|
+
.where(Sequel.|({ type: FP_TYPES }, Sequel.~(nid: exe['nodes'].keys)))
|
705
745
|
.delete
|
706
746
|
#
|
707
747
|
# Delete all pointer to vars, their value might have changed,
|
@@ -714,10 +754,14 @@ module Flor
|
|
714
754
|
pointers = exe['nodes']
|
715
755
|
.inject([]) { |a, (nid, node)|
|
716
756
|
|
757
|
+
# add a pointer for each tag
|
758
|
+
|
717
759
|
ts = node['tags']
|
718
760
|
ts.each { |t|
|
719
761
|
a << [ dom, exid, nid, 'tag', t, nil, now, u, nil ] } if ts
|
720
762
|
|
763
|
+
# add a pointer for each var (if nid == '0')
|
764
|
+
|
721
765
|
vs = nid == '0' ? node['vars'] : nil
|
722
766
|
vs.each { |k, v|
|
723
767
|
case v; when Numeric, String, TrueClass, FalseClass, NilClass
|
@@ -729,6 +773,8 @@ module Flor
|
|
729
773
|
a << [ dom, exid, '0', 'var', k, nil, now, u, v ]
|
730
774
|
end } if vs
|
731
775
|
|
776
|
+
# add a pointer for the task if any
|
777
|
+
|
732
778
|
if ta = node['task']
|
733
779
|
tasker = ta['tasker']
|
734
780
|
n = ta['name']; name = n.is_a?(String) ? n : JSON.dump(n)
|
@@ -736,6 +782,29 @@ module Flor
|
|
736
782
|
a << [ dom, exid, nid, 'tasker', tasker, name, now, u, content ]
|
737
783
|
end
|
738
784
|
|
785
|
+
# add a pointer for the error if any
|
786
|
+
|
787
|
+
if fa = node['failure']
|
788
|
+
|
789
|
+
#puts "-" * 80; pp node; puts "-" * 80
|
790
|
+
a <<
|
791
|
+
if er = fa['error']
|
792
|
+
ni = fa['from'] || nid # not nid /!\
|
793
|
+
nam = "#{er['kla']} l#{er['lin']}"
|
794
|
+
val = er['msg']
|
795
|
+
con = { error: fa, nid: ni }
|
796
|
+
[ dom, exid, ni, 'failure', nam, val, now, u, con ]
|
797
|
+
else
|
798
|
+
nam = fa['tasker'] || 'failure'
|
799
|
+
val = [ fa['attl'] || [], fa['attd'] || {} ]
|
800
|
+
.collect(&:inspect).join(' ')
|
801
|
+
con = { error: fa, nid: nid }
|
802
|
+
[ dom, exid, nid, 'failure', nam, val, now, u, con ]
|
803
|
+
end
|
804
|
+
end
|
805
|
+
|
806
|
+
# done
|
807
|
+
|
739
808
|
a }
|
740
809
|
|
741
810
|
cps = @db[:flor_pointers] # current pointers
|
@@ -747,20 +816,14 @@ module Flor
|
|
747
816
|
#
|
748
817
|
# don't insert when already inserted
|
749
818
|
|
750
|
-
#if pointer_columns.include?(:content)
|
751
819
|
pointers.each { |ptr| c = ptr[8]; ptr[8] = to_blob(c) if c }
|
752
|
-
|
753
|
-
# pointers.each { |ptr| ptr.pop }
|
754
|
-
#end
|
755
|
-
|
756
|
-
#@db[:flor_pointers]
|
757
|
-
# .import(
|
758
|
-
# pointer_columns,
|
759
|
-
# pointers)
|
820
|
+
|
760
821
|
@db[:flor_pointers]
|
761
822
|
.import(
|
762
823
|
POINTER_COLUMNS,
|
763
824
|
pointers)
|
825
|
+
|
826
|
+
callback(:pointers, :update, exid)
|
764
827
|
end
|
765
828
|
|
766
829
|
#def pointer_columns
|
@@ -809,6 +872,23 @@ module Flor
|
|
809
872
|
.inject([]) { |a, elt| a << [ a.last, elt ].compact.join('.'); a }
|
810
873
|
end
|
811
874
|
|
875
|
+
def callback(table, action, *rest)
|
876
|
+
|
877
|
+
(@callbacks[table] || [])
|
878
|
+
.each { |as, block|
|
879
|
+
call_back(block, table, action, *rest) \
|
880
|
+
if as.empty? || as.include?(action) }
|
881
|
+
end
|
882
|
+
|
883
|
+
def call_back(block, table, action, *rest)
|
884
|
+
|
885
|
+
block.call(
|
886
|
+
*(
|
887
|
+
block.arity < 0 ?
|
888
|
+
[ table, action, *rest ] :
|
889
|
+
[ table, action, *rest ][0, block.arity]))
|
890
|
+
end
|
891
|
+
|
812
892
|
class DbLogger
|
813
893
|
|
814
894
|
def initialize(unit); @unit = unit; end
|
data/lib/flor.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Mettraux
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-11-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: munemo
|
@@ -204,6 +204,7 @@ files:
|
|
204
204
|
- lib/flor/pcore/on.rb
|
205
205
|
- lib/flor/pcore/on_cancel.rb
|
206
206
|
- lib/flor/pcore/on_error.rb
|
207
|
+
- lib/flor/pcore/on_receive.rb
|
207
208
|
- lib/flor/pcore/push.rb
|
208
209
|
- lib/flor/pcore/rand.rb
|
209
210
|
- lib/flor/pcore/range.rb
|
@@ -249,6 +250,7 @@ files:
|
|
249
250
|
- lib/flor/to_string.rb
|
250
251
|
- lib/flor/tools/env.rb
|
251
252
|
- lib/flor/tools/firb.rb
|
253
|
+
- lib/flor/tools/flotojson.rb
|
252
254
|
- lib/flor/tools/shell.rb
|
253
255
|
- lib/flor/tools/shell_out.rb
|
254
256
|
- lib/flor/tt.rb
|