rbbt-util 5.11.5 → 5.11.6
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/lib/rbbt/persist.rb +21 -9
- data/lib/rbbt/tsv/parallel/traverse.rb +13 -6
- data/lib/rbbt/util/misc.rb +0 -31
- data/lib/rbbt/util/misc/concurrent_stream.rb +52 -31
- data/lib/rbbt/util/misc/lock.rb +6 -3
- data/lib/rbbt/util/misc/pipes.rb +52 -29
- data/lib/rbbt/util/open.rb +2 -2
- data/lib/rbbt/workflow/accessor.rb +1 -1
- data/lib/rbbt/workflow/step.rb +40 -334
- data/lib/rbbt/workflow/step/run.rb +325 -0
- data/share/rbbt_commands/workflow/task +7 -3
- data/test/rbbt/test_persist.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2230976fc29ab61ab320c1c007521196acaa9b5f
|
4
|
+
data.tar.gz: 60ea71f47e8afa071cdc84f7de115487ec0b1ac5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8f7bbea5678b31d6f49ce13f94dd0b7d3271ae6e187ea837265e202ee90e95c3cb8af27ae5ba8c05b3dd8fa5d0d6eca14ae7870685990ae391fdfb1273ddbac8
|
7
|
+
data.tar.gz: d4746fa8d4393a9f7c399ae766b1881bc41568793ed50722a4b4f101a54962146fead34931b393c8ca44b3ea17057f59b21f505d7336939b777ede2983f9ddc9
|
data/lib/rbbt/persist.rb
CHANGED
@@ -292,12 +292,14 @@ module Persist
|
|
292
292
|
|
293
293
|
return (persist_options[:repo] || Persist::MEMORY)[persist_options[:file]] ||= yield if type ==:memory and persist_options[:file] and persist_options[:persist] and persist_options[:persist] != :update
|
294
294
|
|
295
|
-
if FalseClass
|
295
|
+
if FalseClass == persist_options[:persist]
|
296
|
+
yield
|
297
|
+
else
|
296
298
|
other_options = Misc.process_options persist_options, :other
|
297
299
|
path = persistence_path(name, persist_options, other_options || {})
|
298
300
|
|
299
301
|
case
|
300
|
-
when type.to_sym
|
302
|
+
when type.to_sym == :memory
|
301
303
|
repo = persist_options[:repo] || Persist::MEMORY
|
302
304
|
repo[path] ||= yield
|
303
305
|
|
@@ -410,7 +412,14 @@ module Persist
|
|
410
412
|
res = tee_stream(res, path, type, res.respond_to?(:callback)? res.callback : nil)
|
411
413
|
ConcurrentStream.setup res do
|
412
414
|
begin
|
413
|
-
lockfile.unlock
|
415
|
+
lockfile.unlock if lockfile.locked?
|
416
|
+
rescue
|
417
|
+
Log.warn "Lockfile exception: " << $!.message
|
418
|
+
end
|
419
|
+
end
|
420
|
+
res.abort_callback = Proc.new do
|
421
|
+
begin
|
422
|
+
lockfile.unlock if lockfile.locked?
|
414
423
|
rescue
|
415
424
|
Log.warn "Lockfile exception: " << $!.message
|
416
425
|
end
|
@@ -425,6 +434,13 @@ module Persist
|
|
425
434
|
Log.warn "Lockfile exception: " << $!.message
|
426
435
|
end
|
427
436
|
end
|
437
|
+
res.abort_callback = Proc.new do
|
438
|
+
begin
|
439
|
+
lockfile.unlock
|
440
|
+
rescue
|
441
|
+
Log.warn "Lockfile exception: " << $!.message
|
442
|
+
end
|
443
|
+
end
|
428
444
|
raise KeepLocked.new res
|
429
445
|
end
|
430
446
|
end
|
@@ -440,21 +456,19 @@ module Persist
|
|
440
456
|
else
|
441
457
|
res.read
|
442
458
|
end
|
459
|
+
res.join if res.respond_to? :join
|
443
460
|
rescue
|
444
461
|
res.abort if res.respond_to? :abort
|
445
462
|
raise $!
|
446
|
-
ensure
|
447
|
-
res.join if res.respond_to? :join
|
448
463
|
end
|
449
464
|
when TSV::Dumper
|
450
465
|
begin
|
451
466
|
io = res.stream
|
452
467
|
res = TSV.open(io)
|
468
|
+
io.join if io.respond_to? :join
|
453
469
|
rescue
|
454
470
|
io.abort if io.respond_to? :abort
|
455
471
|
raise $!
|
456
|
-
ensure
|
457
|
-
io.join if io.respond_to? :join
|
458
472
|
end
|
459
473
|
end
|
460
474
|
|
@@ -472,8 +486,6 @@ module Persist
|
|
472
486
|
end
|
473
487
|
end
|
474
488
|
|
475
|
-
else
|
476
|
-
yield
|
477
489
|
end
|
478
490
|
end
|
479
491
|
|
@@ -83,13 +83,18 @@ module TSV
|
|
83
83
|
def self.traverse_io(io, options = {}, &block)
|
84
84
|
filename = io.filename if io.respond_to? :filename
|
85
85
|
callback = Misc.process_options options, :callback
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
86
|
+
begin
|
87
|
+
if callback
|
88
|
+
TSV::Parser.traverse(io, options) do |k,v|
|
89
|
+
res = yield k, v
|
90
|
+
callback.call res
|
91
|
+
end
|
92
|
+
else
|
93
|
+
TSV::Parser.traverse(io, options, &block)
|
90
94
|
end
|
91
|
-
|
92
|
-
|
95
|
+
rescue
|
96
|
+
Log.error "Traverse IO error"
|
97
|
+
raise $!
|
93
98
|
end
|
94
99
|
end
|
95
100
|
|
@@ -305,6 +310,8 @@ module TSV
|
|
305
310
|
rescue Exception
|
306
311
|
Log.exception $!
|
307
312
|
parent.raise $!
|
313
|
+
stream = obj_stream(into)
|
314
|
+
stream.abort if stream and stream.respond_to? :abort
|
308
315
|
end
|
309
316
|
end
|
310
317
|
ConcurrentStream.setup(obj_stream(into), :threads => thread)
|
data/lib/rbbt/util/misc.rb
CHANGED
@@ -546,37 +546,6 @@ end
|
|
546
546
|
res
|
547
547
|
end
|
548
548
|
|
549
|
-
def self.sensiblewrite(path, content = nil, &block)
|
550
|
-
return if File.exists? path
|
551
|
-
tmp_path = path + '.sensible_write'
|
552
|
-
Misc.lock tmp_path do
|
553
|
-
if not File.exists? path
|
554
|
-
FileUtils.rm_f tmp_path if File.exists? tmp_path
|
555
|
-
begin
|
556
|
-
case
|
557
|
-
when block_given?
|
558
|
-
File.open(tmp_path, 'w', &block)
|
559
|
-
when String === content
|
560
|
-
File.open(tmp_path, 'w') do |f| f.write content end
|
561
|
-
when (IO === content or StringIO === content or File === content)
|
562
|
-
File.open(tmp_path, 'w') do |f|
|
563
|
-
while block = content.read(2048);
|
564
|
-
f.write block
|
565
|
-
end
|
566
|
-
end
|
567
|
-
else
|
568
|
-
File.open(tmp_path, 'w') do |f| end
|
569
|
-
end
|
570
|
-
FileUtils.mv tmp_path, path
|
571
|
-
rescue Exception
|
572
|
-
Log.error "Exception in sensiblewrite: #{$!.message} -- #{ Log.color :blue, path }"
|
573
|
-
FileUtils.rm_f tmp_path if File.exists? tmp_path
|
574
|
-
FileUtils.rm_f path if File.exists? path
|
575
|
-
raise $!
|
576
|
-
end
|
577
|
-
end
|
578
|
-
end
|
579
|
-
end
|
580
549
|
|
581
550
|
def self.add_defaults(options, defaults = {})
|
582
551
|
case
|
@@ -1,19 +1,48 @@
|
|
1
1
|
module ConcurrentStream
|
2
2
|
attr_accessor :threads, :pids, :callback, :abort_callback, :filename, :joined
|
3
3
|
|
4
|
+
def self.setup(stream, options = {}, &block)
|
5
|
+
threads, pids, callback, filename = Misc.process_options options, :threads, :pids, :callback, :filename
|
6
|
+
stream.extend ConcurrentStream unless ConcurrentStream === stream
|
7
|
+
|
8
|
+
stream.threads ||= []
|
9
|
+
stream.pids ||= []
|
10
|
+
stream.threads.concat(Array === threads ? threads : [threads]) unless threads.nil?
|
11
|
+
stream.pids.concat(Array === pids ? pids : [pids]) unless pids.nil? or pids.empty?
|
12
|
+
|
13
|
+
callback = block if block_given?
|
14
|
+
if stream.callback and callback
|
15
|
+
old_callback = stream.callback
|
16
|
+
stream.callback = Proc.new do
|
17
|
+
old_callback.call
|
18
|
+
callback.call
|
19
|
+
end
|
20
|
+
else
|
21
|
+
stream.callback = callback
|
22
|
+
end
|
23
|
+
|
24
|
+
stream.filename = filename unless filename.nil?
|
25
|
+
|
26
|
+
stream
|
27
|
+
end
|
28
|
+
|
4
29
|
def joined?
|
5
30
|
@joined
|
6
31
|
end
|
7
32
|
|
8
|
-
def
|
9
|
-
|
33
|
+
def join_threads
|
10
34
|
if @threads and @threads.any?
|
11
35
|
@threads.each do |t|
|
12
|
-
|
36
|
+
begin
|
37
|
+
ensure
|
38
|
+
t.join unless t == Thread.current
|
39
|
+
end
|
13
40
|
end
|
14
41
|
@threads = []
|
15
42
|
end
|
43
|
+
end
|
16
44
|
|
45
|
+
def join_pids
|
17
46
|
if @pids and @pids.any?
|
18
47
|
@pids.each do |pid|
|
19
48
|
begin
|
@@ -24,46 +53,38 @@ module ConcurrentStream
|
|
24
53
|
end
|
25
54
|
@pids = []
|
26
55
|
end
|
56
|
+
end
|
27
57
|
|
58
|
+
def join_callback
|
28
59
|
if @callback and not joined?
|
29
60
|
@callback.call
|
30
61
|
@callback = nil
|
31
62
|
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def join
|
66
|
+
join_threads
|
67
|
+
join_pids
|
68
|
+
|
69
|
+
join_callback
|
32
70
|
|
33
71
|
@joined = true
|
34
72
|
end
|
35
73
|
|
36
|
-
def
|
37
|
-
@threads.each{|t| t.raise Aborted.new unless t
|
38
|
-
|
74
|
+
def abort_threads
|
75
|
+
@threads.each{|t| t.raise Aborted.new unless t == Thread.current } if @threads
|
76
|
+
end
|
77
|
+
|
78
|
+
def abort_pids
|
39
79
|
@pids.each{|pid| Process.kill :INT, pid } if @pids
|
40
|
-
|
80
|
+
end
|
81
|
+
|
82
|
+
def abort
|
83
|
+
abort_threads
|
84
|
+
abort_pids
|
41
85
|
@abort_callback.call if @abort_callback
|
42
86
|
@abort_callback = nil
|
87
|
+
@callback = nil
|
43
88
|
end
|
44
89
|
|
45
|
-
def self.setup(stream, options = {}, &block)
|
46
|
-
threads, pids, callback, filename = Misc.process_options options, :threads, :pids, :callback, :filename
|
47
|
-
stream.extend ConcurrentStream unless ConcurrentStream === stream
|
48
|
-
|
49
|
-
stream.threads ||= []
|
50
|
-
stream.pids ||= []
|
51
|
-
stream.threads.concat(Array === threads ? threads : [threads]) unless threads.nil?
|
52
|
-
stream.pids.concat(Array === pids ? pids : [pids]) unless pids.nil? or pids.empty?
|
53
|
-
|
54
|
-
callback = block if block_given?
|
55
|
-
if stream.callback and callback
|
56
|
-
old_callback = stream.callback
|
57
|
-
stream.callback = Proc.new do
|
58
|
-
old_callback.call
|
59
|
-
callback.call
|
60
|
-
end
|
61
|
-
else
|
62
|
-
stream.callback = callback
|
63
|
-
end
|
64
|
-
|
65
|
-
stream.filename = filename unless filename.nil?
|
66
|
-
|
67
|
-
stream
|
68
|
-
end
|
69
90
|
end
|
data/lib/rbbt/util/misc/lock.rb
CHANGED
@@ -3,14 +3,14 @@ Lockfile.refresh = false if ENV["RBBT_NO_LOCKFILE_REFRESH"] == "true"
|
|
3
3
|
module Misc
|
4
4
|
|
5
5
|
LOCK_MUTEX = Mutex.new
|
6
|
-
def self.lock(file, unlock = true)
|
6
|
+
def self.lock(file, unlock = true, options = {})
|
7
7
|
return yield if file.nil?
|
8
8
|
FileUtils.mkdir_p File.dirname(File.expand_path(file)) unless File.exists? File.dirname(File.expand_path(file))
|
9
9
|
|
10
10
|
res = nil
|
11
11
|
|
12
12
|
lock_path = File.expand_path(file + '.lock')
|
13
|
-
lockfile = Lockfile.new(lock_path)
|
13
|
+
lockfile = Lockfile.new(lock_path, options)
|
14
14
|
|
15
15
|
hostname = Misc.hostname
|
16
16
|
LOCK_MUTEX.synchronize do
|
@@ -28,7 +28,7 @@ module Misc
|
|
28
28
|
end
|
29
29
|
rescue Exception
|
30
30
|
FileUtils.rm lock_path if File.exists? lock_path
|
31
|
-
lockfile = Lockfile.new(lock_path) unless File.exists? lock_path
|
31
|
+
lockfile = Lockfile.new(lock_path, options) unless File.exists? lock_path
|
32
32
|
raise $!
|
33
33
|
end
|
34
34
|
end
|
@@ -43,6 +43,9 @@ module Misc
|
|
43
43
|
rescue KeepLocked
|
44
44
|
unlock = false
|
45
45
|
res = $!.payload
|
46
|
+
rescue Exception
|
47
|
+
lockfile.unlock if lockfile.locked?
|
48
|
+
raise $!
|
46
49
|
ensure
|
47
50
|
if unlock and lockfile.locked?
|
48
51
|
lockfile.unlock
|
data/lib/rbbt/util/misc/pipes.rb
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
module Misc
|
2
2
|
|
3
|
+
class << self
|
4
|
+
attr_accessor :sensiblewrite_dir
|
5
|
+
def sensiblewrite_dir
|
6
|
+
@sensiblewrite_dir = Rbbt.tmp.sensiblewrite
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
3
10
|
PIPE_MUTEX = Mutex.new
|
4
11
|
|
5
12
|
OPEN_PIPE_IN = []
|
@@ -21,7 +28,6 @@ module Misc
|
|
21
28
|
end
|
22
29
|
end
|
23
30
|
|
24
|
-
|
25
31
|
def self.purge_pipes(*save)
|
26
32
|
PIPE_MUTEX.synchronize do
|
27
33
|
OPEN_PIPE_IN.each do |pipe|
|
@@ -43,12 +49,11 @@ module Misc
|
|
43
49
|
sout.close
|
44
50
|
begin
|
45
51
|
yield sin
|
52
|
+
sin.close if close and not sin.closed?
|
46
53
|
rescue
|
47
54
|
Log.exception $!
|
48
55
|
Process.kill :INT, parent_pid
|
49
56
|
Kernel.exit! -1
|
50
|
-
ensure
|
51
|
-
sin.close if close and not sin.closed?
|
52
57
|
end
|
53
58
|
Kernel.exit! 0
|
54
59
|
}
|
@@ -58,10 +63,9 @@ module Misc
|
|
58
63
|
thread = Thread.new(Thread.current) do |parent|
|
59
64
|
begin
|
60
65
|
yield sin
|
66
|
+
sin.close if close and not sin.closed?
|
61
67
|
rescue
|
62
68
|
parent.raise $!
|
63
|
-
ensure
|
64
|
-
sin.close if close and not sin.closed?
|
65
69
|
end
|
66
70
|
end
|
67
71
|
ConcurrentStream.setup sout, :threads => [thread]
|
@@ -84,8 +88,11 @@ module Misc
|
|
84
88
|
begin stream_in1.write block; rescue Exception; Log.exception $!; skip1 = true end unless skip1
|
85
89
|
begin stream_in2.write block; rescue Exception; Log.exception $!; skip2 = true end unless skip2
|
86
90
|
end
|
91
|
+
raise "Error writing in stream_in1" if skip1
|
87
92
|
raise "Error writing in stream_in2" if skip2
|
88
|
-
|
93
|
+
stream.join if stream.respond_to? :join
|
94
|
+
stream_in1.close
|
95
|
+
stream_in2.close
|
89
96
|
rescue Aborted
|
90
97
|
stream.abort if stream.respond_to? :abort
|
91
98
|
raise $!
|
@@ -93,16 +100,11 @@ module Misc
|
|
93
100
|
Log.exception $!
|
94
101
|
rescue Exception
|
95
102
|
Log.exception $!
|
96
|
-
ensure
|
97
|
-
stream_in1.close
|
98
|
-
stream_in2.close
|
99
|
-
stream.join if stream.respond_to? :join
|
100
103
|
end
|
101
104
|
end
|
102
105
|
stream.close
|
103
106
|
stream_in1.close
|
104
107
|
stream_in2.close
|
105
|
-
#stream.join if stream.respond_to? :join
|
106
108
|
|
107
109
|
ConcurrentStream.setup stream_out1, :pids => [splitter_pid]
|
108
110
|
ConcurrentStream.setup stream_out2, :pids => [splitter_pid]
|
@@ -122,18 +124,17 @@ module Misc
|
|
122
124
|
begin stream_in1.write block; rescue Exception; Aborted === $! ? raise($!): Log.exception($!); skip1 = true end unless skip1
|
123
125
|
begin stream_in2.write block; rescue Exception; Aborted === $! ? raise($!): Log.exception($!); skip2 = true end unless skip2
|
124
126
|
end
|
127
|
+
stream_in1.close
|
128
|
+
stream_in2.close
|
129
|
+
stream.join if stream.respond_to? :join
|
125
130
|
rescue Aborted
|
126
131
|
stream.abort if stream.respond_to? :abort
|
127
|
-
raise $!
|
132
|
+
parent.raise $!
|
128
133
|
rescue IOError
|
129
134
|
Log.exception $!
|
130
135
|
rescue Exception
|
131
136
|
Log.exception $!
|
132
137
|
parent.raise $!
|
133
|
-
ensure
|
134
|
-
stream_in1.close
|
135
|
-
stream_in2.close
|
136
|
-
stream.join if stream.respond_to? :join
|
137
138
|
end
|
138
139
|
end
|
139
140
|
|
@@ -153,11 +154,9 @@ module Misc
|
|
153
154
|
while block = io.read(2048)
|
154
155
|
str << block
|
155
156
|
end
|
157
|
+
io.join if io.respond_to? :join
|
156
158
|
rescue
|
157
159
|
io.abort if io.respond_to? :abort
|
158
|
-
ensure
|
159
|
-
io.join if io.respond_to? :join
|
160
|
-
io.close if io.respond_to? :close
|
161
160
|
end
|
162
161
|
str
|
163
162
|
end
|
@@ -167,12 +166,10 @@ module Misc
|
|
167
166
|
while block = io.read(2048)
|
168
167
|
return if io.eof?
|
169
168
|
Thread.pass
|
170
|
-
|
169
|
+
end
|
170
|
+
io.join if io.respond_to? :join
|
171
171
|
rescue
|
172
172
|
io.abort if io.respond_to? :abort
|
173
|
-
ensure
|
174
|
-
io.join if io.respond_to? :join
|
175
|
-
io.close if io.respond_to? :close
|
176
173
|
end
|
177
174
|
end
|
178
175
|
|
@@ -213,12 +210,38 @@ module Misc
|
|
213
210
|
end
|
214
211
|
str
|
215
212
|
end
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
213
|
+
|
214
|
+
def self.sensiblewrite(path, content = nil, &block)
|
215
|
+
return if File.exists? path
|
216
|
+
#tmp_path = path + '.sensible_write'
|
217
|
+
tmp_path = Persist.persistence_path(path, {:dir => Misc.sensiblewrite_dir})
|
218
|
+
Misc.lock tmp_path do
|
219
|
+
if not File.exists? path
|
220
|
+
FileUtils.rm_f tmp_path if File.exists? tmp_path
|
221
|
+
begin
|
222
|
+
case
|
223
|
+
when block_given?
|
224
|
+
File.open(tmp_path, 'w', &block)
|
225
|
+
when String === content
|
226
|
+
File.open(tmp_path, 'w') do |f| f.write content end
|
227
|
+
when (IO === content or StringIO === content or File === content)
|
228
|
+
File.open(tmp_path, 'w') do |f|
|
229
|
+
while block = content.read(2048);
|
230
|
+
f.write block
|
231
|
+
end
|
232
|
+
end
|
233
|
+
else
|
234
|
+
File.open(tmp_path, 'w') do |f| end
|
235
|
+
end
|
236
|
+
FileUtils.mv tmp_path, path
|
237
|
+
rescue Exception
|
238
|
+
Log.error "Exception in sensiblewrite: #{$!.message} -- #{ Log.color :blue, path }"
|
239
|
+
FileUtils.rm_f path if File.exists? path
|
240
|
+
raise $!
|
241
|
+
ensure
|
242
|
+
FileUtils.rm_f tmp_path if File.exists? tmp_path
|
243
|
+
end
|
244
|
+
end
|
220
245
|
end
|
221
|
-
str
|
222
246
|
end
|
223
|
-
|
224
247
|
end
|
data/lib/rbbt/util/open.rb
CHANGED
@@ -236,13 +236,13 @@ module Open
|
|
236
236
|
end
|
237
237
|
end
|
238
238
|
|
239
|
-
def self.lock(file, &block)
|
239
|
+
def self.lock(file, options = {}, &block)
|
240
240
|
if (dir_sub_path = find_repo_dir(file))
|
241
241
|
dir, sub_path = dir_sub_path
|
242
242
|
repo = get_repo_from_dir(dir)
|
243
243
|
Misc.lock_in_repo(repo, sub_path, &block)
|
244
244
|
else
|
245
|
-
Misc.lock(file, &block)
|
245
|
+
Misc.lock(file, true, options, &block)
|
246
246
|
end
|
247
247
|
end
|
248
248
|
|
@@ -73,7 +73,7 @@ class Step
|
|
73
73
|
return nil if @exec or info_file.nil?
|
74
74
|
value = Annotated.purge value if defined? Annotated
|
75
75
|
lock_filename = Persist.persistence_path(info_file, {:dir => Step.lock_dir})
|
76
|
-
Open.lock(info_file) do
|
76
|
+
Open.lock(info_file, :refresh => false) do
|
77
77
|
i = info
|
78
78
|
i[key] = value
|
79
79
|
@info_cache = i
|
data/lib/rbbt/workflow/step.rb
CHANGED
@@ -3,7 +3,7 @@ require 'rbbt/persist/tsv'
|
|
3
3
|
require 'rbbt/util/log'
|
4
4
|
require 'rbbt/util/semaphore'
|
5
5
|
require 'rbbt/workflow/accessor'
|
6
|
-
|
6
|
+
require 'rbbt/workflow/step/run'
|
7
7
|
|
8
8
|
class Step
|
9
9
|
attr_accessor :path, :task, :inputs, :dependencies, :bindings
|
@@ -49,357 +49,63 @@ class Step
|
|
49
49
|
|
50
50
|
class << self
|
51
51
|
attr_accessor :log_relay_step
|
52
|
-
end
|
53
|
-
|
54
|
-
def relay_log(step)
|
55
|
-
return self unless Task === self.task and not self.task.name.nil?
|
56
|
-
if not self.respond_to? :original_log
|
57
|
-
class << self
|
58
|
-
attr_accessor :relay_step
|
59
|
-
alias original_log log
|
60
|
-
def log(status, message = nil)
|
61
|
-
self.status = status
|
62
|
-
message Log.uncolor message
|
63
|
-
relay_step.log([task.name.to_s, status.to_s] * ">", message.nil? ? nil : message ) unless (relay_step.done? or relay_step.error? or relay_step.aborted?)
|
64
|
-
end
|
65
|
-
end
|
66
52
|
end
|
67
|
-
@relay_step = step
|
68
|
-
self
|
69
|
-
end
|
70
53
|
|
71
|
-
def
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
54
|
+
def relay_log(step)
|
55
|
+
return self unless Task === self.task and not self.task.name.nil?
|
56
|
+
if not self.respond_to? :original_log
|
57
|
+
class << self
|
58
|
+
attr_accessor :relay_step
|
59
|
+
alias original_log log
|
60
|
+
def log(status, message = nil)
|
61
|
+
self.status = status
|
62
|
+
message Log.uncolor message
|
63
|
+
relay_step.log([task.name.to_s, status.to_s] * ">", message.nil? ? nil : message ) unless (relay_step.done? or relay_step.error? or relay_step.aborted?)
|
80
64
|
end
|
81
|
-
array
|
82
|
-
when :tsv
|
83
|
-
TSV.open(value)
|
84
|
-
else
|
85
|
-
value.read
|
86
65
|
end
|
87
|
-
rescue Exception
|
88
|
-
value.abort if value.respond_to? :abort
|
89
|
-
ensure
|
90
|
-
value.join if value.respond_to? :join
|
91
|
-
value.close unless value.closed?
|
92
66
|
end
|
93
|
-
|
94
|
-
value
|
95
|
-
when (Annotated === value and info.empty?)
|
96
|
-
value
|
97
|
-
when Annotated === value
|
98
|
-
annotations = value.annotations
|
99
|
-
info.each do |k,v|
|
100
|
-
value.send("#{h}=", v) if annotations.include? k
|
101
|
-
end
|
102
|
-
value
|
103
|
-
else
|
104
|
-
Entity.formats[description].setup(value, info.merge(:format => description))
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def get_stream
|
109
|
-
@mutex.synchronize do
|
110
|
-
begin
|
111
|
-
IO === @result ? @result : nil
|
112
|
-
ensure
|
113
|
-
@result = nil
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def _exec
|
119
|
-
@exec = true if @exec.nil?
|
120
|
-
@task.exec_in((bindings ? bindings : self), *@inputs)
|
121
|
-
end
|
122
|
-
|
123
|
-
def exec(no_load=false)
|
124
|
-
dependencies.each{|dependency| dependency.exec(no_load) }
|
125
|
-
@result = _exec
|
126
|
-
@result = @result.stream if TSV::Dumper === @result
|
127
|
-
no_load ? @result : prepare_result(@result, @task.result_description)
|
128
|
-
end
|
129
|
-
|
130
|
-
def join
|
131
|
-
stream = get_stream if @result
|
132
|
-
begin
|
133
|
-
Misc.consume_stream stream if stream
|
134
|
-
rescue
|
135
|
-
stream.abort if stream.respond_to? :abort
|
136
|
-
raise $!
|
137
|
-
ensure
|
138
|
-
stream.join if stream.respond_to? :join and not stream.joined?
|
139
|
-
end
|
140
|
-
|
141
|
-
return if not Open.exists? info_file
|
142
|
-
@pid ||= info[:pid]
|
143
|
-
|
144
|
-
#while not done?
|
145
|
-
# Misc.insist 2, 0.5 do
|
146
|
-
# raise "Job error while joining: #{info[:messages].last}" if error?
|
147
|
-
# raise "Job aborted while joining: #{info[:messages].last}" if aborted?
|
148
|
-
# raise "Job vanished while joining: #{@pid}" if @pid and not Misc.pid_exists? @pid
|
149
|
-
# end
|
150
|
-
#end
|
151
|
-
|
152
|
-
Misc.insist [0.1, 0.2, 0.5, 1] do
|
153
|
-
@pid ||= info[:pid]
|
154
|
-
end
|
155
|
-
|
156
|
-
if @pid.nil?
|
157
|
-
dependencies.each{|dep| dep.join }
|
158
|
-
self
|
159
|
-
else
|
160
|
-
begin
|
161
|
-
Log.debug{"Waiting for pid: #{@pid}"}
|
162
|
-
Process.waitpid @pid
|
163
|
-
rescue Errno::ECHILD
|
164
|
-
Log.debug{"Process #{ @pid } already finished: #{ path }"}
|
165
|
-
end if Misc.pid_exists? @pid
|
166
|
-
@pid = nil
|
167
|
-
dependencies.each{|dep| dep.join }
|
67
|
+
@relay_step = step
|
168
68
|
self
|
169
69
|
end
|
170
|
-
self
|
171
|
-
end
|
172
|
-
|
173
|
-
def checks
|
174
|
-
rec_dependencies.collect{|dependency| dependency.path }.uniq
|
175
|
-
end
|
176
70
|
|
177
|
-
def
|
178
|
-
|
179
|
-
|
180
|
-
Log.medium("Killing children: #{ children_pids * ", " }")
|
181
|
-
children_pids.each do |pid|
|
182
|
-
Log.medium("Killing child #{ pid }")
|
71
|
+
def prepare_result(value, description = nil, info = {})
|
72
|
+
case
|
73
|
+
when IO === value
|
183
74
|
begin
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
def run_dependencies(seen = [])
|
193
|
-
seen << self.path
|
194
|
-
dependencies.uniq.each{|dependency|
|
195
|
-
next if seen.include? dependency.path
|
196
|
-
Log.info "#{Log.color :magenta, "Checking dependency"} #{Log.color :yellow, task.name.to_s || ""} => #{Log.color :yellow, dependency.task_name.to_s || ""} -- #{Log.color :blue, dependency.path}"
|
197
|
-
begin
|
198
|
-
dependency.relay_log self
|
199
|
-
dependency.clean if not dependency.done? and (dependency.error? or dependency.aborted?)
|
200
|
-
dependency.clean if dependency.streaming? and not dependency.running?
|
201
|
-
#dependency.run_dependencies(seen)
|
202
|
-
dependency.run(ENV["RBBT_NO_STREAM"] != 'true') unless dependency.result or dependency.done?
|
203
|
-
seen << dependency.path
|
204
|
-
seen.concat dependency.rec_dependencies.collect{|d| d.path}
|
205
|
-
rescue Exception
|
206
|
-
backtrace = $!.backtrace
|
207
|
-
set_info :backtrace, backtrace
|
208
|
-
log(:error, "Exception processing dependency #{Log.color :yellow, dependency.task.name.to_s} -- #{$!.class}: #{$!.message}")
|
209
|
-
raise $!
|
210
|
-
end
|
211
|
-
}
|
212
|
-
end
|
213
|
-
|
214
|
-
def run(no_load = false)
|
215
|
-
|
216
|
-
result = nil
|
217
|
-
begin
|
218
|
-
@mutex.synchronize do
|
219
|
-
no_load = no_load ? :stream : false
|
220
|
-
result = Persist.persist "Job", @task.result_type, :file => path, :check => checks, :no_load => no_load do |lockfile|
|
221
|
-
if Step === Step.log_relay_step and not self == Step.log_relay_step
|
222
|
-
relay_log(Step.log_relay_step) unless self.respond_to? :relay_step and self.relay_step
|
223
|
-
end
|
224
|
-
@exec = false
|
225
|
-
|
226
|
-
Open.rm info_file if Open.exists? info_file
|
227
|
-
|
228
|
-
set_info :pid, Process.pid
|
229
|
-
set_info :issued, Time.now
|
230
|
-
|
231
|
-
log(:preparing, "Preparing job: #{Misc.fingerprint dependencies}")
|
232
|
-
set_info :dependencies, dependencies.collect{|dep| [dep.task_name, dep.name]}
|
233
|
-
|
234
|
-
run_dependencies
|
235
|
-
|
236
|
-
set_info :inputs, Misc.remove_long_items(Misc.zip2hash(task.inputs, @inputs)) unless task.inputs.nil?
|
237
|
-
|
238
|
-
set_info :started, (start_time = Time.now)
|
239
|
-
log :started, "#{Log.color :green, "Starting task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}]"
|
240
|
-
|
241
|
-
begin
|
242
|
-
result = _exec
|
243
|
-
rescue Aborted
|
244
|
-
log(:error, "Aborted")
|
245
|
-
|
246
|
-
kill_children
|
247
|
-
raise $!
|
248
|
-
rescue Exception
|
249
|
-
backtrace = $!.backtrace
|
250
|
-
|
251
|
-
# HACK: This fixes an strange behaviour in 1.9.3 where some
|
252
|
-
# backtrace strings are coded in ASCII-8BIT
|
253
|
-
kill_children
|
254
|
-
set_info :backtrace, backtrace
|
255
|
-
log(:error, "#{$!.class}: #{$!.message}")
|
256
|
-
backtrace.each{|l| l.force_encoding("UTF-8")} if String.instance_methods.include? :force_encoding
|
257
|
-
raise $!
|
258
|
-
end
|
259
|
-
|
260
|
-
result = prepare_result result, @task.description, info if IO === result and ENV["RBBT_NO_STREAM"]
|
261
|
-
result = prepare_result result.stream, @task.description, info if TSV::Dumper === result and ENV["RBBT_NO_STREAM"]
|
262
|
-
|
263
|
-
case result
|
264
|
-
when IO
|
265
|
-
result = Misc.read_stream(result) if ENV["RBBT_NO_STREAM"]
|
266
|
-
|
267
|
-
log :streaming, "#{Log.color :magenta, "Streaming task result IO"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}]"
|
268
|
-
ConcurrentStream.setup result do
|
269
|
-
begin
|
270
|
-
set_info :done, (done_time = Time.now)
|
271
|
-
set_info :time_elapsed, (time_elapsed = done_time - start_time)
|
272
|
-
log :done, "#{Log.color :red, "Completed task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] +#{time_elapsed.to_i} -- #{path}"
|
273
|
-
rescue
|
274
|
-
Log.exception $!
|
275
|
-
ensure
|
276
|
-
join
|
277
|
-
end
|
278
|
-
end
|
279
|
-
result.abort_callback = Proc.new do
|
280
|
-
begin
|
281
|
-
log :error, "#{Log.color :red, "ERROR -- streamming aborted"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] -- #{path}"
|
282
|
-
rescue
|
283
|
-
Log.exception $!
|
284
|
-
ensure
|
285
|
-
join
|
286
|
-
end
|
287
|
-
end
|
288
|
-
when TSV::Dumper
|
289
|
-
log :streaming, "#{Log.color :magenta, "Streaming task result TSV::Dumper"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}]"
|
290
|
-
ConcurrentStream.setup result.stream do
|
291
|
-
begin
|
292
|
-
set_info :done, (done_time = Time.now)
|
293
|
-
set_info :done, (done_time = Time.now)
|
294
|
-
set_info :time_elapsed, (time_elapsed = done_time - start_time)
|
295
|
-
log :done, "#{Log.color :red, "Completed task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] +#{time_elapsed.to_i} -- #{path}"
|
296
|
-
rescue
|
297
|
-
Log.exception $!
|
298
|
-
ensure
|
299
|
-
join
|
300
|
-
end
|
301
|
-
end
|
302
|
-
result.stream.abort_callback = Proc.new do
|
303
|
-
begin
|
304
|
-
log :error, "#{Log.color :red, "ERROR -- streamming aborted"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] -- #{path}"
|
305
|
-
rescue
|
306
|
-
Log.exception $!
|
307
|
-
end
|
75
|
+
case @task.result_type
|
76
|
+
when :array
|
77
|
+
array = []
|
78
|
+
while line = value.gets
|
79
|
+
array << line.strip
|
308
80
|
end
|
81
|
+
array
|
82
|
+
when :tsv
|
83
|
+
TSV.open(value)
|
309
84
|
else
|
310
|
-
|
311
|
-
set_info :time_elapsed, (time_elapsed = done_time - start_time)
|
312
|
-
log :done, "#{Log.color :red, "Completed task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] +#{time_elapsed.to_i}"
|
85
|
+
value.read
|
313
86
|
end
|
314
|
-
|
315
|
-
|
316
|
-
end
|
317
|
-
|
318
|
-
if no_load
|
319
|
-
@result ||= result
|
320
|
-
self
|
321
|
-
else
|
322
|
-
@result = prepare_result result, @task.result_description
|
323
|
-
end
|
324
|
-
end
|
325
|
-
ensure
|
326
|
-
join unless no_load
|
327
|
-
end
|
328
|
-
end
|
329
|
-
|
330
|
-
def fork(semaphore = nil)
|
331
|
-
raise "Can not fork: Step is waiting for proces #{@pid} to finish" if not @pid.nil? and not Process.pid == @pid
|
332
|
-
@pid = Process.fork do
|
333
|
-
begin
|
334
|
-
RbbtSemaphore.wait_semaphore(semaphore) if semaphore
|
335
|
-
FileUtils.mkdir_p File.dirname(path) unless Open.exists? File.dirname(path)
|
336
|
-
begin
|
337
|
-
res = run
|
338
|
-
rescue Aborted
|
339
|
-
Log.debug{"Forked process aborted: #{path}"}
|
340
|
-
log :aborted, "Aborted"
|
341
|
-
raise $!
|
342
|
-
rescue Exception
|
343
|
-
Log.debug("Exception '#{$!.message}' caught on forked process: #{path}")
|
344
|
-
raise $!
|
345
|
-
ensure
|
346
|
-
join
|
347
|
-
end
|
348
|
-
|
349
|
-
begin
|
350
|
-
children_pids = info[:children_pids]
|
351
|
-
if children_pids
|
352
|
-
children_pids.each do |pid|
|
353
|
-
if Misc.pid_exists? pid
|
354
|
-
begin
|
355
|
-
Process.waitpid pid
|
356
|
-
rescue Errno::ECHILD
|
357
|
-
Log.low "Waiting on #{ pid } failed: #{$!.message}"
|
358
|
-
end
|
359
|
-
end
|
360
|
-
end
|
361
|
-
set_info :children_done, Time.now
|
362
|
-
end
|
363
|
-
rescue Exception
|
364
|
-
Log.debug("Exception waiting for children: #{$!.message}")
|
365
|
-
exit -1
|
366
|
-
end
|
367
|
-
set_info :pid, nil
|
368
|
-
exit 0
|
87
|
+
rescue Exception
|
88
|
+
value.abort if value.respond_to? :abort
|
369
89
|
ensure
|
370
|
-
|
90
|
+
value.join if value.respond_to? :join
|
91
|
+
value.close unless value.closed?
|
371
92
|
end
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
#return true unless info[:forked]
|
382
|
-
|
383
|
-
case @pid
|
384
|
-
when nil
|
385
|
-
Log.medium "Could not abort #{path}: no pid"
|
386
|
-
false
|
387
|
-
when Process.pid
|
388
|
-
Log.medium "Could not abort #{path}: same process"
|
389
|
-
false
|
390
|
-
else
|
391
|
-
Log.medium "Aborting #{path}: #{ @pid }"
|
392
|
-
begin
|
393
|
-
Process.kill("KILL", @pid)
|
394
|
-
Process.waitpid @pid
|
395
|
-
rescue Exception
|
396
|
-
Log.debug("Aborted job #{@pid} was not killed: #{$!.message}")
|
93
|
+
when (not defined? Entity or description.nil? or not Entity.formats.include? description)
|
94
|
+
value
|
95
|
+
when (Annotated === value and info.empty?)
|
96
|
+
value
|
97
|
+
when Annotated === value
|
98
|
+
annotations = value.annotations
|
99
|
+
info.each do |k,v|
|
100
|
+
value.send("#{h}=", v) if annotations.include? k
|
397
101
|
end
|
398
|
-
|
399
|
-
|
102
|
+
value
|
103
|
+
else
|
104
|
+
Entity.formats[description].setup(value, info.merge(:format => description))
|
400
105
|
end
|
401
106
|
end
|
402
107
|
|
108
|
+
|
403
109
|
def child(&block)
|
404
110
|
child_pid = Process.fork &block
|
405
111
|
children_pids = info[:children_pids]
|
@@ -0,0 +1,325 @@
|
|
1
|
+
class Step
|
2
|
+
|
3
|
+
attr_reader :stream
|
4
|
+
|
5
|
+
def get_stream
|
6
|
+
@mutex.synchronize do
|
7
|
+
@stream = begin
|
8
|
+
IO === @result ? @result : nil
|
9
|
+
ensure
|
10
|
+
@result = nil
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def _exec
|
16
|
+
@exec = true if @exec.nil?
|
17
|
+
@task.exec_in((bindings ? bindings : self), *@inputs)
|
18
|
+
end
|
19
|
+
|
20
|
+
def exec(no_load=false)
|
21
|
+
dependencies.each{|dependency| dependency.exec(no_load) }
|
22
|
+
@result = _exec
|
23
|
+
@result = @result.stream if TSV::Dumper === @result
|
24
|
+
no_load ? @result : prepare_result(@result, @task.result_description)
|
25
|
+
end
|
26
|
+
|
27
|
+
def checks
|
28
|
+
rec_dependencies.collect{|dependency| dependency.path }.uniq
|
29
|
+
end
|
30
|
+
|
31
|
+
def kill_children
|
32
|
+
children_pids = info[:children_pids]
|
33
|
+
if children_pids and children_pids.any?
|
34
|
+
Log.medium("Killing children: #{ children_pids * ", " }")
|
35
|
+
children_pids.each do |pid|
|
36
|
+
Log.medium("Killing child #{ pid }")
|
37
|
+
begin
|
38
|
+
Process.kill "INT", pid
|
39
|
+
rescue Exception
|
40
|
+
Log.medium("Exception killing child #{ pid }: #{$!.message}")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def run_dependencies(seen = [])
|
47
|
+
seen << self.path
|
48
|
+
dependencies.uniq.each{|dependency|
|
49
|
+
next if seen.include? dependency.path
|
50
|
+
Log.info "#{Log.color :magenta, "Checking dependency"} #{Log.color :yellow, task.name.to_s || ""} => #{Log.color :yellow, dependency.task_name.to_s || ""} -- #{Log.color :blue, dependency.path}"
|
51
|
+
begin
|
52
|
+
dependency.relay_log self
|
53
|
+
dependency.clean if not dependency.done? and (dependency.error? or dependency.aborted?)
|
54
|
+
dependency.clean if dependency.streaming? and not dependency.running?
|
55
|
+
#dependency.run_dependencies(seen)
|
56
|
+
dependency.run(ENV["RBBT_NO_STREAM"] != 'true') unless dependency.result or dependency.done?
|
57
|
+
seen << dependency.path
|
58
|
+
seen.concat dependency.rec_dependencies.collect{|d| d.path}
|
59
|
+
rescue Exception
|
60
|
+
backtrace = $!.backtrace
|
61
|
+
set_info :backtrace, backtrace
|
62
|
+
log(:error, "Exception processing dependency #{Log.color :yellow, dependency.task.name.to_s} -- #{$!.class}: #{$!.message}")
|
63
|
+
raise $!
|
64
|
+
end
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
def run(no_load = false)
|
69
|
+
|
70
|
+
result = nil
|
71
|
+
begin
|
72
|
+
@mutex.synchronize do
|
73
|
+
no_load = no_load ? :stream : false
|
74
|
+
result = Persist.persist "Job", @task.result_type, :file => path, :check => checks, :no_load => no_load do |lockfile|
|
75
|
+
if Step === Step.log_relay_step and not self == Step.log_relay_step
|
76
|
+
relay_log(Step.log_relay_step) unless self.respond_to? :relay_step and self.relay_step
|
77
|
+
end
|
78
|
+
@exec = false
|
79
|
+
|
80
|
+
Open.rm info_file if Open.exists? info_file
|
81
|
+
|
82
|
+
set_info :pid, Process.pid
|
83
|
+
set_info :issued, Time.now
|
84
|
+
|
85
|
+
log(:preparing, "Preparing job: #{Misc.fingerprint dependencies}")
|
86
|
+
set_info :dependencies, dependencies.collect{|dep| [dep.task_name, dep.name]}
|
87
|
+
|
88
|
+
run_dependencies
|
89
|
+
|
90
|
+
set_info :inputs, Misc.remove_long_items(Misc.zip2hash(task.inputs, @inputs)) unless task.inputs.nil?
|
91
|
+
|
92
|
+
set_info :started, (start_time = Time.now)
|
93
|
+
log :started, "#{Log.color :green, "Starting task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}]"
|
94
|
+
|
95
|
+
begin
|
96
|
+
result = _exec
|
97
|
+
rescue Aborted
|
98
|
+
log(:error, "Aborted")
|
99
|
+
|
100
|
+
kill_children
|
101
|
+
raise $!
|
102
|
+
rescue Exception
|
103
|
+
backtrace = $!.backtrace
|
104
|
+
|
105
|
+
# HACK: This fixes an strange behaviour in 1.9.3 where some
|
106
|
+
# backtrace strings are coded in ASCII-8BIT
|
107
|
+
kill_children
|
108
|
+
set_info :backtrace, backtrace
|
109
|
+
log(:error, "#{$!.class}: #{$!.message}")
|
110
|
+
backtrace.each{|l| l.force_encoding("UTF-8")} if String.instance_methods.include? :force_encoding
|
111
|
+
raise $!
|
112
|
+
end
|
113
|
+
|
114
|
+
result = prepare_result result, @task.description, info if IO === result and ENV["RBBT_NO_STREAM"]
|
115
|
+
result = prepare_result result.stream, @task.description, info if TSV::Dumper === result and ENV["RBBT_NO_STREAM"]
|
116
|
+
|
117
|
+
case result
|
118
|
+
when IO
|
119
|
+
result = Misc.read_stream(result) if ENV["RBBT_NO_STREAM"]
|
120
|
+
|
121
|
+
log :streaming, "#{Log.color :magenta, "Streaming task result IO"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}]"
|
122
|
+
ConcurrentStream.setup result do
|
123
|
+
begin
|
124
|
+
set_info :done, (done_time = Time.now)
|
125
|
+
set_info :time_elapsed, (time_elapsed = done_time - start_time)
|
126
|
+
log :done, "#{Log.color :red, "Completed task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] +#{time_elapsed.to_i} -- #{path}"
|
127
|
+
rescue
|
128
|
+
Log.exception $!
|
129
|
+
ensure
|
130
|
+
join
|
131
|
+
end
|
132
|
+
end
|
133
|
+
result.abort_callback = Proc.new do
|
134
|
+
begin
|
135
|
+
log :error, "#{Log.color :red, "ERROR -- streamming aborted"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] -- #{path}" if status == :streaming
|
136
|
+
stop_dependencies
|
137
|
+
abort_stream
|
138
|
+
rescue
|
139
|
+
Log.exception $!
|
140
|
+
ensure
|
141
|
+
join
|
142
|
+
end
|
143
|
+
end
|
144
|
+
when TSV::Dumper
|
145
|
+
log :streaming, "#{Log.color :magenta, "Streaming task result TSV::Dumper"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}]"
|
146
|
+
ConcurrentStream.setup result.stream do
|
147
|
+
begin
|
148
|
+
set_info :done, (done_time = Time.now)
|
149
|
+
set_info :done, (done_time = Time.now)
|
150
|
+
set_info :time_elapsed, (time_elapsed = done_time - start_time)
|
151
|
+
log :done, "#{Log.color :red, "Completed task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] +#{time_elapsed.to_i} -- #{path}"
|
152
|
+
rescue
|
153
|
+
Log.exception $!
|
154
|
+
ensure
|
155
|
+
join
|
156
|
+
end
|
157
|
+
end
|
158
|
+
result.stream.abort_callback = Proc.new do
|
159
|
+
begin
|
160
|
+
log :error, "#{Log.color :red, "ERROR -- streamming aborted"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] -- #{path}" if status == :streaming
|
161
|
+
stop_dependencies
|
162
|
+
abort_stream
|
163
|
+
rescue
|
164
|
+
Log.exception $!
|
165
|
+
ensure
|
166
|
+
join
|
167
|
+
end
|
168
|
+
end
|
169
|
+
else
|
170
|
+
set_info :done, (done_time = Time.now)
|
171
|
+
set_info :time_elapsed, (time_elapsed = done_time - start_time)
|
172
|
+
log :done, "#{Log.color :red, "Completed task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] +#{time_elapsed.to_i}"
|
173
|
+
end
|
174
|
+
|
175
|
+
result
|
176
|
+
end
|
177
|
+
|
178
|
+
if no_load
|
179
|
+
@result ||= result
|
180
|
+
self
|
181
|
+
else
|
182
|
+
@result = prepare_result result, @task.result_description
|
183
|
+
end
|
184
|
+
end
|
185
|
+
ensure
|
186
|
+
join unless no_load
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def fork(semaphore = nil)
|
191
|
+
raise "Can not fork: Step is waiting for proces #{@pid} to finish" if not @pid.nil? and not Process.pid == @pid
|
192
|
+
@pid = Process.fork do
|
193
|
+
begin
|
194
|
+
RbbtSemaphore.wait_semaphore(semaphore) if semaphore
|
195
|
+
FileUtils.mkdir_p File.dirname(path) unless Open.exists? File.dirname(path)
|
196
|
+
begin
|
197
|
+
res = run
|
198
|
+
rescue Aborted
|
199
|
+
Log.debug{"Forked process aborted: #{path}"}
|
200
|
+
log :aborted, "Aborted"
|
201
|
+
raise $!
|
202
|
+
rescue Exception
|
203
|
+
Log.debug("Exception '#{$!.message}' caught on forked process: #{path}")
|
204
|
+
raise $!
|
205
|
+
ensure
|
206
|
+
join
|
207
|
+
end
|
208
|
+
|
209
|
+
begin
|
210
|
+
children_pids = info[:children_pids]
|
211
|
+
if children_pids
|
212
|
+
children_pids.each do |pid|
|
213
|
+
if Misc.pid_exists? pid
|
214
|
+
begin
|
215
|
+
Process.waitpid pid
|
216
|
+
rescue Errno::ECHILD
|
217
|
+
Log.low "Waiting on #{ pid } failed: #{$!.message}"
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
set_info :children_done, Time.now
|
222
|
+
end
|
223
|
+
rescue Exception
|
224
|
+
Log.debug("Exception waiting for children: #{$!.message}")
|
225
|
+
exit -1
|
226
|
+
end
|
227
|
+
set_info :pid, nil
|
228
|
+
exit 0
|
229
|
+
ensure
|
230
|
+
RbbtSemaphore.post_semaphore(semaphore) if semaphore
|
231
|
+
end
|
232
|
+
end
|
233
|
+
set_info :forked, true
|
234
|
+
Process.detach(@pid)
|
235
|
+
self
|
236
|
+
end
|
237
|
+
|
238
|
+
def stop_dependencies
|
239
|
+
dependencies.each do |dep|
|
240
|
+
dep.abort unless dep.done?
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def abort_pid
|
245
|
+
@pid ||= info[:pid]
|
246
|
+
|
247
|
+
case @pid
|
248
|
+
when nil
|
249
|
+
Log.medium "Could not abort #{path}: no pid"
|
250
|
+
false
|
251
|
+
when Process.pid
|
252
|
+
Log.medium "Could not abort #{path}: same process"
|
253
|
+
false
|
254
|
+
else
|
255
|
+
Log.medium "Aborting #{path}: #{ @pid }"
|
256
|
+
begin
|
257
|
+
Process.kill("KILL", @pid)
|
258
|
+
Process.waitpid @pid
|
259
|
+
rescue Exception
|
260
|
+
Log.debug("Aborted job #{@pid} was not killed: #{$!.message}")
|
261
|
+
end
|
262
|
+
true
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
def abort_stream
|
267
|
+
stream = get_stream if @result
|
268
|
+
stream ||= @stream
|
269
|
+
if stream
|
270
|
+
stream.abort if stream.respond_to? :abort
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def abort
|
275
|
+
begin
|
276
|
+
abort_pid
|
277
|
+
stop_dependencies
|
278
|
+
abort_stream
|
279
|
+
ensure
|
280
|
+
log(:aborted, "Job aborted")
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
def join_stream
|
285
|
+
stream = get_stream if @result
|
286
|
+
if stream
|
287
|
+
begin
|
288
|
+
Misc.consume_stream stream
|
289
|
+
stream.join if stream.respond_to? :join # and not stream.joined?
|
290
|
+
rescue Exception
|
291
|
+
stream.abort if stream.respond_to? :abort
|
292
|
+
self.abort
|
293
|
+
raise $!
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
def join
|
299
|
+
|
300
|
+
join_stream
|
301
|
+
|
302
|
+
return if not Open.exists? info_file
|
303
|
+
@pid ||= info[:pid]
|
304
|
+
|
305
|
+
Misc.insist [0.1, 0.2, 0.5, 1] do
|
306
|
+
@pid ||= info[:pid]
|
307
|
+
end
|
308
|
+
|
309
|
+
if @pid.nil?
|
310
|
+
dependencies.each{|dep| dep.join }
|
311
|
+
self
|
312
|
+
else
|
313
|
+
begin
|
314
|
+
Log.debug{"Waiting for pid: #{@pid}"}
|
315
|
+
Process.waitpid @pid
|
316
|
+
rescue Errno::ECHILD
|
317
|
+
Log.debug{"Process #{ @pid } already finished: #{ path }"}
|
318
|
+
end if Misc.pid_exists? @pid
|
319
|
+
@pid = nil
|
320
|
+
dependencies.each{|dep| dep.join }
|
321
|
+
self
|
322
|
+
end
|
323
|
+
self
|
324
|
+
end
|
325
|
+
end
|
@@ -413,9 +413,13 @@ when Step
|
|
413
413
|
end unless io.closed?
|
414
414
|
io.join if io.respond_to? :join
|
415
415
|
rescue Exception
|
416
|
-
|
417
|
-
|
418
|
-
|
416
|
+
Log.exception $!
|
417
|
+
begin
|
418
|
+
io.abort if io.respond_to? :abort
|
419
|
+
io.join
|
420
|
+
ensure
|
421
|
+
exit -1
|
422
|
+
end
|
419
423
|
end
|
420
424
|
else
|
421
425
|
res.join
|
data/test/rbbt/test_persist.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbbt-util
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.11.
|
4
|
+
version: 5.11.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Miguel Vazquez
|
@@ -205,6 +205,7 @@ files:
|
|
205
205
|
- lib/rbbt/workflow/doc.rb
|
206
206
|
- lib/rbbt/workflow/soap.rb
|
207
207
|
- lib/rbbt/workflow/step.rb
|
208
|
+
- lib/rbbt/workflow/step/run.rb
|
208
209
|
- lib/rbbt/workflow/task.rb
|
209
210
|
- lib/rbbt/workflow/usage.rb
|
210
211
|
- share/Rlib/util.R
|