flor 1.2.2 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|