rbbt-util 5.11.5 → 5.11.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|