flor 1.4.0 → 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 +6 -0
- data/lib/flor/core/node.rb +1 -1
- data/lib/flor/core/procedure.rb +39 -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 +28 -2
- data/lib/flor/unit/logger.rb +2 -1
- data/lib/flor/unit/scheduler.rb +21 -21
- data/lib/flor/unit/storage.rb +77 -23
- data/lib/flor.rb +1 -1
- metadata +3 -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
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
|
data/lib/flor/core/procedure.rb
CHANGED
@@ -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
|
@@ -982,6 +991,36 @@ class Flor::Procedure < Flor::Node
|
|
982
991
|
|
983
992
|
[]
|
984
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
|
985
1024
|
end
|
986
1025
|
|
987
1026
|
|
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
|
+
|
data/lib/flor/tools/flotojson.rb
CHANGED
@@ -16,7 +16,16 @@ if (ARGV & [ '-h', '--help']).any?
|
|
16
16
|
puts " turns a flor .flo process definition to its tree representation"
|
17
17
|
puts
|
18
18
|
puts " flags:"
|
19
|
-
puts " --pp
|
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"
|
20
29
|
puts
|
21
30
|
exit 0
|
22
31
|
end
|
@@ -53,11 +62,28 @@ end
|
|
53
62
|
# end
|
54
63
|
|
55
64
|
fname = files.first
|
56
|
-
|
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
|
+
|
57
74
|
tree = Flor.parse(content, fname, {})
|
58
75
|
|
59
76
|
if flags['--pp']
|
60
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)
|
61
87
|
else
|
62
88
|
puts JSON.dump(tree)
|
63
89
|
end
|
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
|
|
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
|
@@ -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 }
|
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)
|
@@ -418,26 +424,29 @@ module Flor
|
|
418
424
|
now = Flor.tstamp
|
419
425
|
u = @unit.identifier
|
420
426
|
|
421
|
-
|
427
|
+
id =
|
428
|
+
synchronize do
|
422
429
|
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
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)
|
441
450
|
|
442
451
|
@unit.wake_up
|
443
452
|
|
@@ -502,6 +511,8 @@ module Flor
|
|
502
511
|
munit: u)
|
503
512
|
end
|
504
513
|
|
514
|
+
callback(:traps, :insert, id)
|
515
|
+
|
505
516
|
traps[id]
|
506
517
|
|
507
518
|
rescue => err
|
@@ -548,6 +559,21 @@ module Flor
|
|
548
559
|
nil
|
549
560
|
end
|
550
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
|
+
|
551
577
|
protected
|
552
578
|
|
553
579
|
def migration_table_and_column(opts={})
|
@@ -640,10 +666,11 @@ module Flor
|
|
640
666
|
def reschedule_timer(t)
|
641
667
|
|
642
668
|
w = { id: t.id.to_i, status: 'active', mtime: t.mtime, munit: t.munit }
|
669
|
+
r = nil
|
643
670
|
|
644
671
|
if t.type != 'at' && t.type != 'in'
|
645
672
|
|
646
|
-
@db[:flor_timers]
|
673
|
+
r = @db[:flor_timers]
|
647
674
|
.where(w)
|
648
675
|
.update(
|
649
676
|
count: t.count.to_i + 1,
|
@@ -652,9 +679,11 @@ module Flor
|
|
652
679
|
mtime: Flor.tstamp,
|
653
680
|
munit: @unit.identifier)
|
654
681
|
|
682
|
+
callback(:timers, :update, w, t)
|
683
|
+
|
655
684
|
elsif @archive
|
656
685
|
|
657
|
-
@db[:flor_timers]
|
686
|
+
r = @db[:flor_timers]
|
658
687
|
.where(w)
|
659
688
|
.update(
|
660
689
|
count: t.count.to_i + 1,
|
@@ -662,12 +691,18 @@ module Flor
|
|
662
691
|
mtime: Flor.tstamp,
|
663
692
|
munit: @unit.identifier)
|
664
693
|
|
694
|
+
callback(:timers, :update, w, t)
|
695
|
+
|
665
696
|
else
|
666
697
|
|
667
|
-
@db[:flor_timers]
|
698
|
+
r = @db[:flor_timers]
|
668
699
|
.where(w)
|
669
700
|
.delete
|
701
|
+
|
702
|
+
callback(:timers, :delete, w, t)
|
670
703
|
end
|
704
|
+
|
705
|
+
r
|
671
706
|
end
|
672
707
|
|
673
708
|
def remove_nodes(exe, status, now)
|
@@ -787,6 +822,8 @@ module Flor
|
|
787
822
|
.import(
|
788
823
|
POINTER_COLUMNS,
|
789
824
|
pointers)
|
825
|
+
|
826
|
+
callback(:pointers, :update, exid)
|
790
827
|
end
|
791
828
|
|
792
829
|
#def pointer_columns
|
@@ -835,6 +872,23 @@ module Flor
|
|
835
872
|
.inject([]) { |a, elt| a << [ a.last, elt ].compact.join('.'); a }
|
836
873
|
end
|
837
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
|
+
|
838
892
|
class DbLogger
|
839
893
|
|
840
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-
|
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
|