flor 1.0.1 → 1.1.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 +9 -0
- data/lib/flor.rb +1 -1
- data/lib/flor/core/texecutor.rb +26 -1
- data/lib/flor/flor.rb +19 -6
- data/lib/flor/log.rb +1 -0
- data/lib/flor/tools/firb.rb +33 -0
- data/lib/flor/tools/shell.rb +12 -3
- data/lib/flor/unit.rb +1 -0
- data/lib/flor/unit/caller.rb +6 -4
- data/lib/flor/unit/executor.rb +18 -13
- data/lib/flor/unit/ganger.rb +3 -0
- data/lib/flor/unit/gangers.rb +125 -0
- data/lib/flor/unit/loader.rb +42 -10
- data/lib/flor/unit/logger.rb +11 -2
- data/lib/flor/unit/models/message.rb +5 -0
- data/lib/flor/unit/scheduler.rb +13 -8
- data/lib/flor/unit/storage.rb +46 -42
- data/lib/flor/unit/taskers.rb +68 -0
- data/lib/flor/unit/waiter.rb +2 -2
- 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: 62c06708e2abc35f1b43c2cf9ecaf73d5f89633433c60af3864450d91ccabf47
|
4
|
+
data.tar.gz: 33d4531561c77d0f43cd97a51775d1079a41885650df73583c26050846177087
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b27557dcfbf250d1b0af9c4220a140b66e84aceb0506d947a51a1440fabf385f21b2ce125c08178bf68d5c13b87ee3d9967fdf0a46d5ef3b473991b3329139c4
|
7
|
+
data.tar.gz: 48fdc31b116360526afa4fe6b40e0b550c04bc451085aac55005f28add44bb30802029218f73fd898965b54f2a88acb95eb9420e73ca83d494b9fed1fdf64cf7
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,15 @@
|
|
2
2
|
# CHANGELOG.md
|
3
3
|
|
4
4
|
|
5
|
+
## flor 1.1.0 released 2021-01-06
|
6
|
+
|
7
|
+
* Introduce Tasker #set_payload and #set_vars
|
8
|
+
* Introduce the ModuleGanger
|
9
|
+
* Allow for domain/dot.json taskers
|
10
|
+
* Introduce Flor::StagedBasicTasker
|
11
|
+
* Fix service/executor issue in Caller
|
12
|
+
|
13
|
+
|
5
14
|
## flor 1.0.1 released 2020-11-23
|
6
15
|
|
7
16
|
* Accept sto_uri strings pointing to constant like 'DB'
|
data/lib/flor.rb
CHANGED
data/lib/flor/core/texecutor.rb
CHANGED
@@ -254,7 +254,7 @@ module Flor
|
|
254
254
|
o.each { |ee| ee['_path'] = path if ee.is_a?(Hash) }
|
255
255
|
end
|
256
256
|
|
257
|
-
o
|
257
|
+
rework_conf(o)
|
258
258
|
end
|
259
259
|
|
260
260
|
def interpret_path(path, context=nil)
|
@@ -299,6 +299,31 @@ module Flor
|
|
299
299
|
|
300
300
|
ps.last == 'etc' ? File.absolute_path(File.join(dir, '..')) : dir
|
301
301
|
end
|
302
|
+
|
303
|
+
protected
|
304
|
+
|
305
|
+
# For now, only the return procedure has to be marshalled back
|
306
|
+
# to the "return" string, gh-36
|
307
|
+
#
|
308
|
+
def rework_conf(o)
|
309
|
+
|
310
|
+
case o
|
311
|
+
when Array
|
312
|
+
o.collect { |e|
|
313
|
+
rework_conf(e) }
|
314
|
+
when Hash
|
315
|
+
o.inject({}) { |h, (k, v)|
|
316
|
+
h[k] =
|
317
|
+
if Flor.is_proc_tree?(v) && v[1]['proc'] == 'return'
|
318
|
+
'return'
|
319
|
+
else
|
320
|
+
rework_conf(v)
|
321
|
+
end
|
322
|
+
h }
|
323
|
+
else
|
324
|
+
o
|
325
|
+
end
|
326
|
+
end
|
302
327
|
end
|
303
328
|
end
|
304
329
|
end
|
data/lib/flor/flor.rb
CHANGED
@@ -20,7 +20,7 @@ module Flor
|
|
20
20
|
signal cancel
|
21
21
|
terminated failed ceased
|
22
22
|
idle
|
23
|
-
|
23
|
+
].freeze
|
24
24
|
|
25
25
|
class << self
|
26
26
|
|
@@ -279,13 +279,19 @@ module Flor
|
|
279
279
|
#
|
280
280
|
# functions about time
|
281
281
|
|
282
|
+
# Used by the storage in its next_time endeavours
|
283
|
+
#
|
284
|
+
def tstam
|
285
|
+
Time.now.utc.strftime('%FT%T')
|
286
|
+
end
|
287
|
+
|
282
288
|
def isostamp(show_date, show_time, show_usec, time)
|
283
289
|
|
284
290
|
t = (time || Time.now).utc
|
285
291
|
s = StringIO.new
|
286
292
|
|
287
|
-
s << t.strftime('%
|
288
|
-
s << t.strftime('T%
|
293
|
+
s << t.strftime('%F') if show_date # YYYY-mm-dd
|
294
|
+
s << t.strftime('T%T') if show_time # THH:MM:SS
|
289
295
|
s << sprintf('.%06d', t.usec) if show_time && show_usec
|
290
296
|
s << 'Z' if show_time
|
291
297
|
|
@@ -367,11 +373,18 @@ module Flor
|
|
367
373
|
sub_domain?(dom, sub)
|
368
374
|
end
|
369
375
|
|
376
|
+
def dot_join(*elts)
|
377
|
+
|
378
|
+
elts.collect(&:to_s).select { |e| e.length > 0 }.join('.')
|
379
|
+
end
|
380
|
+
|
370
381
|
def sub_domain?(dom, sub)
|
371
382
|
|
372
|
-
dom
|
373
|
-
|
374
|
-
|
383
|
+
d = dom.is_a?(Array) ? dot_join(*dom) : dom.to_s
|
384
|
+
|
385
|
+
d == '' ||
|
386
|
+
sub == d ||
|
387
|
+
sub[0, d.length + 1] == d + '.'
|
375
388
|
end
|
376
389
|
alias subdomain? sub_domain?
|
377
390
|
|
data/lib/flor/log.rb
CHANGED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'irb'
|
4
|
+
|
5
|
+
#require 'sequel'
|
6
|
+
require 'flor'
|
7
|
+
require 'flor/unit'
|
8
|
+
|
9
|
+
|
10
|
+
p [ RUBY_VERSION, RUBY_PLATFORM ]
|
11
|
+
|
12
|
+
puts
|
13
|
+
|
14
|
+
ENV.each do |k, v|
|
15
|
+
next unless k.match?(/RUBY|GEM/)
|
16
|
+
puts "* #{k}: #{v}"
|
17
|
+
end
|
18
|
+
|
19
|
+
ARGV.each do |arg|
|
20
|
+
if arg.match(/:/)
|
21
|
+
DB = Sequel.connect(arg)
|
22
|
+
p DB
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
#MODELS = [ :executions, :timers, :traces, :traps, :pointers, :messages ]
|
27
|
+
if defined?(DB)
|
28
|
+
Flor::Message.dataset = DB[:flor_messages]
|
29
|
+
end
|
30
|
+
|
31
|
+
ARGV.clear
|
32
|
+
IRB.start
|
33
|
+
|
data/lib/flor/tools/shell.rb
CHANGED
@@ -15,11 +15,16 @@ module Flor::Tools
|
|
15
15
|
def initialize(argv=nil)
|
16
16
|
|
17
17
|
env = ENV['FLOR_ENV'] || 'shell'
|
18
|
-
|
18
|
+
|
19
|
+
@root = File.directory?(env) ? env : "envs/#{env}"
|
19
20
|
|
20
21
|
prepare_home
|
21
22
|
|
22
|
-
|
23
|
+
over_conf = {}
|
24
|
+
#
|
25
|
+
c = ENV['FLOR_STO_URI']; over_conf['sto_uri'] = c if c
|
26
|
+
|
27
|
+
@unit = Flor::Unit.new("#{@root}/etc/conf.json", over_conf)
|
23
28
|
|
24
29
|
@unit.conf['unit'] = 'cli'
|
25
30
|
#unit.hooker.add('journal', Flor::Journal)
|
@@ -31,7 +36,11 @@ module Flor::Tools
|
|
31
36
|
@mute = false
|
32
37
|
@paging = true
|
33
38
|
|
34
|
-
|
39
|
+
if ENV['FLOR_NO_START']
|
40
|
+
@unit.check_migration_version
|
41
|
+
else
|
42
|
+
@unit.start
|
43
|
+
end
|
35
44
|
|
36
45
|
@flow_path = File.join(@root, 'home/scratch.flo')
|
37
46
|
@ra_flow_path = File.join(@root, 'home/ra_scratch.flo')
|
data/lib/flor/unit.rb
CHANGED
data/lib/flor/unit/caller.rb
CHANGED
@@ -107,9 +107,11 @@ module Flor
|
|
107
107
|
#
|
108
108
|
# call
|
109
109
|
|
110
|
-
|
111
|
-
|
112
|
-
ms =
|
110
|
+
pt = message['point']
|
111
|
+
|
112
|
+
ms = [ "call_#{pt}", "on_#{pt}", :on_message, :on, pt ]
|
113
|
+
ms = ms + [ :on_cancel, :cancel ] if pt == 'detask'
|
114
|
+
|
113
115
|
m = ms.find { |mm| o.respond_to?(mm) }
|
114
116
|
|
115
117
|
fail(
|
@@ -121,7 +123,7 @@ module Flor
|
|
121
123
|
case o.method(m).arity
|
122
124
|
when 1 then o.send(m, message)
|
123
125
|
when 2 then o.send(m, conf, message)
|
124
|
-
when 3 then o.send(m,
|
126
|
+
when 3 then o.send(m, service, conf, message)
|
125
127
|
when -1 then o.send(m, {
|
126
128
|
service: service, configuration: conf, message: message })
|
127
129
|
else o.send(m)
|
data/lib/flor/unit/executor.rb
CHANGED
@@ -109,15 +109,13 @@ module Flor
|
|
109
109
|
rescue Exception => exc
|
110
110
|
|
111
111
|
# TODO eventually, have a dump dir
|
112
|
+
|
112
113
|
fn =
|
113
|
-
[
|
114
|
-
'
|
115
|
-
@unit.conf['env'], @unit.identifier, @exid,
|
116
|
-
'r' + counter('runs').to_s
|
117
|
-
].collect(&:to_s).join('_') + '.dump'
|
114
|
+
[ 'flor', @unit.conf['env'], @unit.identifier, @exid,
|
115
|
+
'r' + counter('runs').to_s ].collect(&:to_s).join('_') + '.dump'
|
118
116
|
|
119
117
|
@unit.logger.error(
|
120
|
-
"#{self.class}#do_run()", exc, "(dumping to #{fn})")
|
118
|
+
"#{self.class}#do_run()", exc, "(dumping to #{fn} ...)")
|
121
119
|
|
122
120
|
File.open(fn, 'wb') do |f|
|
123
121
|
f.puts(Flor.to_pretty_s({
|
@@ -134,19 +132,26 @@ module Flor
|
|
134
132
|
f.puts(on_do_run_exc(exc))
|
135
133
|
end
|
136
134
|
|
135
|
+
@unit.logger.error(
|
136
|
+
"#{self.class}#do_run()", exc, "(dumped to #{fn})")
|
137
|
+
|
137
138
|
#puts on_do_run_exc(exc)
|
138
139
|
# dump notification above
|
139
140
|
end
|
140
141
|
|
141
142
|
def task(message)
|
142
143
|
|
143
|
-
|
144
|
-
|
145
|
-
message
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
144
|
+
if message['routed'] == false
|
145
|
+
|
146
|
+
t = message['tasker']
|
147
|
+
n = node(message['nid'])
|
148
|
+
|
149
|
+
msg = n['heat0'] != t ?
|
150
|
+
"tasker #{t.inspect} not found" :
|
151
|
+
"don't know how to apply #{t.inspect}"
|
152
|
+
|
153
|
+
return error_reply(n, message, msg)
|
154
|
+
end
|
150
155
|
|
151
156
|
@unit.ganger.task(self, message)
|
152
157
|
end
|
data/lib/flor/unit/ganger.rb
CHANGED
@@ -54,6 +54,9 @@ module Flor
|
|
54
54
|
(@unit.loader.tasker(domain, 'ganger', message) ||
|
55
55
|
@unit.loader.tasker(domain, 'tasker', message))) ||
|
56
56
|
@unit.loader.tasker(domain, tname, message)
|
57
|
+
#puts "=" * 80
|
58
|
+
#pp tconf
|
59
|
+
#puts "=" * 80
|
57
60
|
|
58
61
|
fail ArgumentError.new(
|
59
62
|
"tasker #{tname.inspect} not found"
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Flor
|
4
|
+
|
5
|
+
# A ModuleGanger accepts a `module:` conf entry that points to a Ruby
|
6
|
+
# module. The tasker implementations are searched for among the classes
|
7
|
+
# in the given module.
|
8
|
+
#
|
9
|
+
# Among the tasker classes (classes that respond to on_task, on_detask, ...)
|
10
|
+
# it selects the first tasker that matches the tasker name.
|
11
|
+
#
|
12
|
+
class ModuleGanger
|
13
|
+
|
14
|
+
def initialize(service, conf, message)
|
15
|
+
|
16
|
+
@service = service
|
17
|
+
@conf = conf
|
18
|
+
@message = message
|
19
|
+
end
|
20
|
+
|
21
|
+
def task
|
22
|
+
|
23
|
+
tas = @message['tasker']
|
24
|
+
clas = list_tasker_classes
|
25
|
+
cla = clas.find { |c| tasker_name(c) == tas }
|
26
|
+
|
27
|
+
return [ Flor.dup_and_merge(@message, 'routed' => false) ] \
|
28
|
+
unless cla
|
29
|
+
|
30
|
+
call_tasker(cla)
|
31
|
+
end
|
32
|
+
|
33
|
+
alias detask task
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def list_tasker_classes
|
38
|
+
|
39
|
+
mod_name = @conf['module']
|
40
|
+
|
41
|
+
fail ArgumentError.new('ganger module: configuration entry missing') \
|
42
|
+
unless mod_name
|
43
|
+
|
44
|
+
mod = Flor.const_lookup(mod_name) rescue nil
|
45
|
+
|
46
|
+
fail ArgumentError.new("ganger cannot find module #{mod_name.inspect}") \
|
47
|
+
unless mod
|
48
|
+
|
49
|
+
list_classes(mod, [])
|
50
|
+
end
|
51
|
+
|
52
|
+
def list_classes(start, r)
|
53
|
+
|
54
|
+
# place leave classes on top if possible
|
55
|
+
# within a level, sort alphabetically
|
56
|
+
|
57
|
+
clas = start.constants.collect { |co| start.const_get(co) }
|
58
|
+
clas, mods = clas.partition { |c| c.is_a?(Class) }
|
59
|
+
|
60
|
+
mods.each { |m| list_classes(m, r) }
|
61
|
+
r.concat(clas.select { |c| tasker?(c) }.sort_by { |c| c.name })
|
62
|
+
|
63
|
+
r
|
64
|
+
end
|
65
|
+
|
66
|
+
TASKER_METHODS = [
|
67
|
+
:on, :on_message,
|
68
|
+
:task, :on_task,
|
69
|
+
:detask, :on_detask, :cancel, :on_cancel
|
70
|
+
].freeze
|
71
|
+
|
72
|
+
def tasker?(cla)
|
73
|
+
|
74
|
+
return true if (TASKER_METHODS & cla.public_instance_methods).any?
|
75
|
+
return true if (TASKER_METHODS & cla.public_methods).any?
|
76
|
+
false
|
77
|
+
end
|
78
|
+
|
79
|
+
def tasker_name(cla)
|
80
|
+
|
81
|
+
if cla.public_instance_methods.include?(:tasker_name)
|
82
|
+
|
83
|
+
unless cla.respond_to?(:_ganged)
|
84
|
+
class << cla
|
85
|
+
attr_accessor :_ganged
|
86
|
+
end
|
87
|
+
cla._ganged = cla.allocate
|
88
|
+
end
|
89
|
+
|
90
|
+
call_tasker_name(cla._ganged)
|
91
|
+
|
92
|
+
elsif cla.public_methods.include?(:tasker_name)
|
93
|
+
|
94
|
+
call_tasker_name(cla)
|
95
|
+
|
96
|
+
else
|
97
|
+
|
98
|
+
cla.name.split('::').last.gsub(/Tasker\z/, '')
|
99
|
+
.gsub(/([a-z])([A-Z])/) { |_| $1 + '_' + $2.downcase }
|
100
|
+
.gsub(/([A-Z])/) { |c| c.downcase }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def call_tasker_name(o)
|
105
|
+
|
106
|
+
case i = o.method(:tasker_name).arity
|
107
|
+
when 1 then o.tasker_name(@message)
|
108
|
+
when 2 then o.tasker_name(@conf, @message)
|
109
|
+
when 3 then o.tasker_name(@service, @conf, @message)
|
110
|
+
when -1 then o.tasker_name(
|
111
|
+
service: @service, conf: @conf, message: @message)
|
112
|
+
else o.tasker_name
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def call_tasker(c)
|
117
|
+
|
118
|
+
cnf = @conf.merge('class' => c)
|
119
|
+
|
120
|
+
@service.unit.caller
|
121
|
+
.call(@service, cnf, @message)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
data/lib/flor/unit/loader.rb
CHANGED
@@ -46,7 +46,7 @@ module Flor
|
|
46
46
|
.collect { |pa| [ pa, expose_d(pa, {}) ] }
|
47
47
|
.select { |pa, d| Flor.sub_domain?(d, domain) }
|
48
48
|
.sort_by { |pa, d| d.count('.') }
|
49
|
-
.inject({}) { |vars, (pa, _)| vars.merge!(
|
49
|
+
.inject({}) { |vars, (pa, _)| vars.merge!(eval_variables(pa, {})) }
|
50
50
|
end
|
51
51
|
|
52
52
|
#def procedures(path)
|
@@ -87,25 +87,28 @@ module Flor
|
|
87
87
|
.select { |pa| pa.index('/lib/taskers/') }
|
88
88
|
.collect { |pa| [ pa, *expose_dn(pa, {}) ] }
|
89
89
|
.select { |pa, d, n|
|
90
|
-
Flor.sub_domain?([ d, n ]
|
90
|
+
Flor.sub_domain?([ d, n ], domain) ||
|
91
91
|
(n == name && Flor.sub_domain?(d, domain)) }
|
92
92
|
.sort_by { |pa, d, n| d.count('.') }
|
93
93
|
.last
|
94
94
|
|
95
95
|
return nil unless pat
|
96
96
|
|
97
|
-
conf =
|
97
|
+
conf = eval_tasker_conf(pat, message)
|
98
98
|
|
99
99
|
return conf if nam == name
|
100
100
|
|
101
|
-
|
101
|
+
cnf = conf[name]
|
102
102
|
|
103
|
-
return nil unless
|
103
|
+
return nil unless cnf
|
104
104
|
|
105
|
-
|
106
|
-
|
105
|
+
extras = conf.select { |_, v| ! v.is_a?(Hash) }
|
106
|
+
extras['_path'] = pat
|
107
107
|
|
108
|
-
|
108
|
+
(cnf.is_a?(Array) ? cnf : [ cnf ])
|
109
|
+
.each { |h| h.merge!(extras) }
|
110
|
+
|
111
|
+
cnf
|
109
112
|
end
|
110
113
|
|
111
114
|
def hooks(domain)
|
@@ -119,8 +122,8 @@ module Flor
|
|
119
122
|
.select { |pa, d| Flor.sub_domain?(d, domain) }
|
120
123
|
.sort_by { |pa, d| d.count('.') }
|
121
124
|
.collect { |pa, d|
|
122
|
-
|
123
|
-
.each_with_index { |h, i| h['_path'] = pa
|
125
|
+
eval_hook_conf(pa, {})
|
126
|
+
.each_with_index { |h, i| h['_path'] = "#{pa}:#{i}" } }
|
124
127
|
.flatten(1)
|
125
128
|
end
|
126
129
|
|
@@ -247,6 +250,35 @@ module Flor
|
|
247
250
|
end
|
248
251
|
end
|
249
252
|
|
253
|
+
def eval_variables(path, context)
|
254
|
+
eval(path, context)
|
255
|
+
end
|
256
|
+
def eval_tasker_conf(path, context)
|
257
|
+
eval(path, context)
|
258
|
+
end
|
259
|
+
# TODO like in eval_hook_conf, reject fautly tasker confs...
|
260
|
+
# TODO like in eval_hook_conf, reject fautly variables...
|
261
|
+
|
262
|
+
def eval_hook_conf(path, context)
|
263
|
+
|
264
|
+
a = eval(path, context)
|
265
|
+
|
266
|
+
fail ArgumentError.new(
|
267
|
+
"hook conf at #{path} must be an array of hashes"
|
268
|
+
) unless a.is_a?(Array)
|
269
|
+
|
270
|
+
a.each do |e|
|
271
|
+
fail ArgumentError.new(
|
272
|
+
"hook conf at #{path} has non-hash entry #{e.inspect}"
|
273
|
+
) unless e.is_a?(Hash)
|
274
|
+
fail ArgumentError.new(
|
275
|
+
"hook conf at #{path} has incorrect point #{e['point'].inspect}"
|
276
|
+
) unless e['point'].is_a?(String)
|
277
|
+
end
|
278
|
+
|
279
|
+
a
|
280
|
+
end
|
281
|
+
|
250
282
|
def eval(path, context)
|
251
283
|
|
252
284
|
ext =
|
data/lib/flor/unit/logger.rb
CHANGED
@@ -71,7 +71,8 @@ module Flor
|
|
71
71
|
dbi = ' ' + dbi if dbi.length > 0
|
72
72
|
|
73
73
|
txt = elts.collect(&:to_s).join(' ')
|
74
|
-
|
74
|
+
|
75
|
+
err = find_err(elts)
|
75
76
|
|
76
77
|
head = "#{stp} #{@uni}#{dbi} #{lvl} "
|
77
78
|
|
@@ -198,7 +199,8 @@ module Flor
|
|
198
199
|
|
199
200
|
return unless @unit.conf['log_err']
|
200
201
|
|
201
|
-
|
202
|
+
s = Flor.msg_to_detail_s(executor, message, opts.merge(flag: true))
|
203
|
+
@out.puts(s) if s
|
202
204
|
end
|
203
205
|
|
204
206
|
def log_src(source, opts, log_opts={})
|
@@ -245,6 +247,13 @@ module Flor
|
|
245
247
|
message[0..k + 2 + 4] + "(...len#{i - (k + 2 + 1)})" + message[i..-1]
|
246
248
|
end
|
247
249
|
|
250
|
+
def find_err(elts)
|
251
|
+
|
252
|
+
elts.find { |e| e.is_a?(Exception) } ||
|
253
|
+
(defined?(Java) &&
|
254
|
+
elts.find { |e| e.class.ancestors.include?(Java::JavaLang::Error) })
|
255
|
+
end
|
256
|
+
|
248
257
|
class Out
|
249
258
|
|
250
259
|
attr_reader :unit
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
|
3
4
|
module Flor
|
4
5
|
|
5
6
|
class Message < FlorModel
|
@@ -19,6 +20,10 @@ module Flor
|
|
19
20
|
#
|
20
21
|
# index :exid
|
21
22
|
#end
|
23
|
+
|
24
|
+
def nid; data['nid']; end
|
25
|
+
def tasker; data['tasker']; end
|
26
|
+
alias payload data
|
22
27
|
end
|
23
28
|
end
|
24
29
|
|
data/lib/flor/unit/scheduler.rb
CHANGED
@@ -138,11 +138,7 @@ module Flor
|
|
138
138
|
|
139
139
|
# TODO heartbeat, every x minutes, when idle, log something
|
140
140
|
|
141
|
-
|
142
|
-
"database not ready, " +
|
143
|
-
"db ver: #{@storage.db_version.inspect}, " +
|
144
|
-
"mig ver: #{@storage.migration_version}"
|
145
|
-
) if !! @conf['sto_migration_check'] && @storage.ready?
|
141
|
+
check_migration_version
|
146
142
|
|
147
143
|
@thread_status = :running
|
148
144
|
|
@@ -162,6 +158,15 @@ module Flor
|
|
162
158
|
self
|
163
159
|
end
|
164
160
|
|
161
|
+
def check_migration_version
|
162
|
+
|
163
|
+
fail(
|
164
|
+
"database not ready, " +
|
165
|
+
"db ver: #{@storage.db_version.inspect}, " +
|
166
|
+
"mig ver: #{@storage.migration_version}"
|
167
|
+
) if !! @conf['sto_migration_check'] && @storage.ready?
|
168
|
+
end
|
169
|
+
|
165
170
|
def stop
|
166
171
|
|
167
172
|
@thread_status = :stop
|
@@ -590,7 +595,7 @@ module Flor
|
|
590
595
|
|
591
596
|
rescue Exception => ex
|
592
597
|
|
593
|
-
puts
|
598
|
+
puts(on_start_exc(ex))
|
594
599
|
end
|
595
600
|
|
596
601
|
def prepare_message(point, args)
|
@@ -678,9 +683,9 @@ module Flor
|
|
678
683
|
def should_wake_up?
|
679
684
|
|
680
685
|
return true if @wake_up
|
681
|
-
return true if Time.now - @reloaded_at >= reload_after
|
686
|
+
return true if (Time.now - @reloaded_at) >= reload_after
|
682
687
|
|
683
|
-
@next_time && @next_time <= Flor.
|
688
|
+
@next_time && (@next_time <= Flor.tstam)
|
684
689
|
end
|
685
690
|
|
686
691
|
def unreserve_messages
|
data/lib/flor/unit/storage.rb
CHANGED
@@ -7,6 +7,14 @@ module Flor
|
|
7
7
|
|
8
8
|
class Storage
|
9
9
|
|
10
|
+
MESSAGE_COLUMNS = [
|
11
|
+
:domain, :exid, :point, :content,
|
12
|
+
:status, :ctime, :mtime, :cunit, :munit
|
13
|
+
].freeze
|
14
|
+
POINTER_COLUMNS = [
|
15
|
+
:domain, :exid, :nid, :type, :name, :value, :ctime, :cunit
|
16
|
+
].freeze
|
17
|
+
|
10
18
|
attr_reader :unit, :db, :models
|
11
19
|
|
12
20
|
attr_reader :mutex
|
@@ -352,8 +360,7 @@ module Flor
|
|
352
360
|
|
353
361
|
@db[:flor_messages]
|
354
362
|
.import(
|
355
|
-
|
356
|
-
:status, :ctime, :mtime, :cunit, :munit ],
|
363
|
+
MESSAGE_COLUMNS,
|
357
364
|
unstored.map { |m|
|
358
365
|
[ Flor.domain(m['exid']), m['exid'], m['point'], to_blob(m),
|
359
366
|
'created', n, n, u, u ] }) \
|
@@ -517,25 +524,6 @@ module Flor
|
|
517
524
|
end
|
518
525
|
end
|
519
526
|
|
520
|
-
def put_task_pointer(msg, tname, tconf)
|
521
|
-
|
522
|
-
exid = msg['exid']
|
523
|
-
dom = Flor.domain(exid)
|
524
|
-
|
525
|
-
synchronize do
|
526
|
-
|
527
|
-
@db[:flor_pointers]
|
528
|
-
.insert(
|
529
|
-
domain: dom,
|
530
|
-
exid: exid,
|
531
|
-
nid: msg['nid'],
|
532
|
-
type: 'tasker',
|
533
|
-
name: tname,
|
534
|
-
ctime: Flor.tstamp,
|
535
|
-
cunit: @unit.identifier)
|
536
|
-
end
|
537
|
-
end
|
538
|
-
|
539
527
|
def fetch_next_time
|
540
528
|
|
541
529
|
t =
|
@@ -598,14 +586,13 @@ module Flor
|
|
598
586
|
|
599
587
|
@db[:flor_messages]
|
600
588
|
.where(
|
601
|
-
id: messages.collect { |m| m['mid'] }.compact)
|
589
|
+
id: messages.collect { |m| m['mid'] }.uniq.compact)
|
602
590
|
.update(
|
603
591
|
status: 'consumed', mtime: n, munit: u)
|
604
592
|
|
605
593
|
@db[:flor_messages]
|
606
594
|
.import(
|
607
|
-
|
608
|
-
:status, :ctime, :mtime, :cunit, :munit ],
|
595
|
+
MESSAGE_COLUMNS,
|
609
596
|
messages
|
610
597
|
.select { |m|
|
611
598
|
! m['mid'] && POINTS_TO_ARCHIVE.include?(m['point']) }
|
@@ -621,19 +608,16 @@ module Flor
|
|
621
608
|
|
622
609
|
@db[:flor_messages]
|
623
610
|
.where(
|
624
|
-
id: messages.collect { |m| m['mid'] }.compact)
|
611
|
+
id: messages.collect { |m| m['mid'] }.uniq.compact)
|
625
612
|
.delete
|
626
613
|
end
|
627
614
|
end
|
628
615
|
|
629
616
|
def load_timers
|
630
617
|
|
631
|
-
now = Flor.tstamp
|
632
|
-
no = now[0, now.rindex('.')]
|
633
|
-
|
634
618
|
timers
|
635
619
|
.where(status: 'active')
|
636
|
-
.where { ntime <=
|
620
|
+
.where { ntime <= Flor.tstam }
|
637
621
|
.order(:ntime)
|
638
622
|
.all
|
639
623
|
|
@@ -703,9 +687,9 @@ module Flor
|
|
703
687
|
|
704
688
|
def update_pointers(exe, status, now)
|
705
689
|
|
706
|
-
# Q
|
707
|
-
#
|
708
|
-
#
|
690
|
+
# Q Should we archive old pointers?
|
691
|
+
# A Well, it might be better to only archive the execution and leave
|
692
|
+
# in there enough information...
|
709
693
|
|
710
694
|
exid = exe['exid']
|
711
695
|
|
@@ -731,23 +715,25 @@ module Flor
|
|
731
715
|
|
732
716
|
ts = node['tags']
|
733
717
|
ts.each { |t|
|
734
|
-
a << [ dom, exid, nid, 'tag', t, nil, now, u ] } if ts
|
718
|
+
a << [ dom, exid, nid, 'tag', t, nil, now, u, nil ] } if ts
|
735
719
|
|
736
720
|
vs = nid == '0' ? node['vars'] : nil
|
737
721
|
vs.each { |k, v|
|
738
722
|
case v; when Numeric, String, TrueClass, FalseClass, NilClass
|
739
|
-
a << [ dom, exid, '0', 'var', k, v.to_s, now, u ]
|
723
|
+
a << [ dom, exid, '0', 'var', k, v.to_s, now, u, nil ]
|
740
724
|
when Array, Hash
|
741
725
|
s = '(array)'; s = '(object)' if v.is_a?(Hash)
|
742
|
-
a << [ dom, exid, '0', 'var', k, s, now, u ]
|
726
|
+
a << [ dom, exid, '0', 'var', k, s, now, u, nil ]
|
743
727
|
else
|
744
|
-
a << [ dom, exid, '0', 'var', k, nil, now, u ]
|
728
|
+
a << [ dom, exid, '0', 'var', k, nil, now, u, nil ]
|
745
729
|
end } if vs
|
746
730
|
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
731
|
+
if ta = node['task']
|
732
|
+
tasker = ta['tasker']
|
733
|
+
name = ta['name']
|
734
|
+
content = { message: node['message'], atts: node['atts'] }
|
735
|
+
a << [ dom, exid, nid, 'tasker', tasker, name, now, u, content ]
|
736
|
+
end
|
751
737
|
|
752
738
|
a }
|
753
739
|
|
@@ -755,17 +741,35 @@ module Flor
|
|
755
741
|
.where(exid: exid)
|
756
742
|
.select(:nid, :type, :name)
|
757
743
|
.all
|
758
|
-
pointers.reject! { |_, _, ni, ty, na, _, _, _|
|
744
|
+
pointers.reject! { |_, _, ni, ty, na, _, _, _, _|
|
759
745
|
cps.find { |cp| cp[:nid] == ni && cp[:type] == ty && cp[:name] == na } }
|
760
746
|
#
|
761
747
|
# don't insert when already inserted
|
762
748
|
|
749
|
+
if pointer_columns.include?(:content)
|
750
|
+
pointers.each { |ptr|
|
751
|
+
c = ptr[8]; ptr[8] = to_blob(c) if c }
|
752
|
+
else
|
753
|
+
pointers.each { |ptr|
|
754
|
+
ptr.pop }
|
755
|
+
end
|
756
|
+
|
763
757
|
@db[:flor_pointers]
|
764
758
|
.import(
|
765
|
-
|
759
|
+
pointer_columns,
|
766
760
|
pointers)
|
767
761
|
end
|
768
762
|
|
763
|
+
def pointer_columns
|
764
|
+
|
765
|
+
@pointer_columns ||=
|
766
|
+
if @db[:flor_pointers].columns.include?(:content)
|
767
|
+
POINTER_COLUMNS + [ :content ]
|
768
|
+
else
|
769
|
+
POINTER_COLUMNS
|
770
|
+
end
|
771
|
+
end
|
772
|
+
|
769
773
|
def determine_type_and_schedule(message)
|
770
774
|
|
771
775
|
t, s = message['type'], message['string']
|
data/lib/flor/unit/taskers.rb
CHANGED
@@ -29,6 +29,29 @@ module Flor
|
|
29
29
|
alias task_name taskname
|
30
30
|
|
31
31
|
def vars; @message['vars']; end
|
32
|
+
alias variables vars
|
33
|
+
|
34
|
+
def set_payload(h)
|
35
|
+
fail TypeError.new("not a hash but a #{fs.class}") unless h.is_a?(Hash)
|
36
|
+
@message['payload'] = h
|
37
|
+
end
|
38
|
+
alias set_fields set_payload
|
39
|
+
|
40
|
+
def set_vars(h)
|
41
|
+
fail TypeError.new("not a hash but a #{fs.class}") unless h.is_a?(Hash)
|
42
|
+
@message['vars'] = h
|
43
|
+
end
|
44
|
+
alias set_variables set_vars
|
45
|
+
|
46
|
+
#def merge_into_payload(h)
|
47
|
+
# @message['payload'].merge(h)
|
48
|
+
#end
|
49
|
+
#alias merge_into_fields merge_into_payload
|
50
|
+
#def merge_into_vars(h)
|
51
|
+
# @message['vars'].merge(h)
|
52
|
+
#end
|
53
|
+
#
|
54
|
+
# no for now, payload.merge(h) and vars.merge(h) do suffice
|
32
55
|
|
33
56
|
def execution
|
34
57
|
|
@@ -112,5 +135,50 @@ module Flor
|
|
112
135
|
h
|
113
136
|
end
|
114
137
|
end
|
138
|
+
|
139
|
+
# A BasicTasker with stages (pre / on / post)
|
140
|
+
#
|
141
|
+
class StagedBasicTasker < BasicTasker
|
142
|
+
|
143
|
+
def call_task
|
144
|
+
|
145
|
+
call_one_of(:pre_task)
|
146
|
+
call_one_of(:on_task, :task)
|
147
|
+
end
|
148
|
+
|
149
|
+
def call_detask
|
150
|
+
|
151
|
+
call_one_of(:pre_detask, :pre_cancel)
|
152
|
+
call_one_of(:on_detask, :on_cancel, :detask, :cancel)
|
153
|
+
end
|
154
|
+
|
155
|
+
protected
|
156
|
+
|
157
|
+
def call_one_of(*ms)
|
158
|
+
|
159
|
+
m = ms.flatten.find { |mm| respond_to?(mm) }
|
160
|
+
|
161
|
+
send(m) if m
|
162
|
+
end
|
163
|
+
|
164
|
+
def reply(message=@message, force=false)
|
165
|
+
|
166
|
+
fail ArgumentError.new(
|
167
|
+
"argument to reply must be a Hash but is #{message.class}"
|
168
|
+
) unless message.is_a?(Hash)
|
169
|
+
|
170
|
+
pt = @message['point']
|
171
|
+
|
172
|
+
ms = [ "post_#{pt}" ]; ms << :post_cancel if pt == 'detask'
|
173
|
+
#
|
174
|
+
call_one_of(ms)
|
175
|
+
|
176
|
+
msg = derive_message(message)
|
177
|
+
|
178
|
+
@ganger.return(msg) if force || @ganger
|
179
|
+
|
180
|
+
[] # very important, return no further messages
|
181
|
+
end
|
182
|
+
end
|
115
183
|
end
|
116
184
|
|
data/lib/flor/unit/waiter.rb
CHANGED
@@ -53,7 +53,7 @@ module Flor
|
|
53
53
|
|
54
54
|
@mutex.synchronize do
|
55
55
|
|
56
|
-
return false unless
|
56
|
+
return false unless msg_match?(message)
|
57
57
|
|
58
58
|
@serie.shift
|
59
59
|
return false if @serie.any?
|
@@ -151,7 +151,7 @@ module Flor
|
|
151
151
|
|
152
152
|
protected
|
153
153
|
|
154
|
-
def
|
154
|
+
def msg_match?(message)
|
155
155
|
|
156
156
|
mpoint = message['point']
|
157
157
|
|
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.0
|
4
|
+
version: 1.1.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:
|
11
|
+
date: 2021-01-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: munemo
|
@@ -248,6 +248,7 @@ files:
|
|
248
248
|
- lib/flor/punit/trap.rb
|
249
249
|
- lib/flor/to_string.rb
|
250
250
|
- lib/flor/tools/env.rb
|
251
|
+
- lib/flor/tools/firb.rb
|
251
252
|
- lib/flor/tools/shell.rb
|
252
253
|
- lib/flor/tools/shell_out.rb
|
253
254
|
- lib/flor/tt.rb
|
@@ -257,6 +258,7 @@ files:
|
|
257
258
|
- lib/flor/unit/dump.rb
|
258
259
|
- lib/flor/unit/executor.rb
|
259
260
|
- lib/flor/unit/ganger.rb
|
261
|
+
- lib/flor/unit/gangers.rb
|
260
262
|
- lib/flor/unit/hloader.rb
|
261
263
|
- lib/flor/unit/hook.rb
|
262
264
|
- lib/flor/unit/hooker.rb
|