rbbt-util 5.13.1 → 5.13.2
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 +10 -35
- data/lib/rbbt/tsv/parallel/traverse.rb +118 -78
- data/lib/rbbt/tsv/parser.rb +6 -4
- data/lib/rbbt/tsv/stream.rb +107 -2
- data/lib/rbbt/tsv/util.rb +7 -15
- data/lib/rbbt/util/concurrency/processes.rb +16 -17
- data/lib/rbbt/util/concurrency/processes/worker.rb +5 -3
- data/lib/rbbt/util/log.rb +2 -1
- data/lib/rbbt/util/log/progress.rb +46 -20
- data/lib/rbbt/util/misc/exceptions.rb +11 -1
- data/lib/rbbt/util/misc/inspect.rb +1 -1
- data/lib/rbbt/util/misc/lock.rb +1 -1
- data/lib/rbbt/util/misc/pipes.rb +66 -25
- data/lib/rbbt/util/semaphore.rb +3 -3
- data/lib/rbbt/workflow/accessor.rb +34 -12
- data/lib/rbbt/workflow/definition.rb +7 -3
- data/lib/rbbt/workflow/step.rb +4 -3
- data/lib/rbbt/workflow/step/run.rb +104 -30
- data/lib/rbbt/workflow/usage.rb +1 -1
- data/share/rbbt_commands/workflow/task +11 -1
- data/test/rbbt/tsv/parallel/test_traverse.rb +31 -34
- data/test/rbbt/tsv/test_filter.rb +6 -6
- data/test/rbbt/util/concurrency/test_processes.rb +0 -1
- metadata +2 -2
data/lib/rbbt/util/semaphore.rb
CHANGED
@@ -81,7 +81,7 @@ void post_semaphore(char* name){
|
|
81
81
|
yield elem
|
82
82
|
end
|
83
83
|
rescue Interrupt
|
84
|
-
Log.
|
84
|
+
Log.warn "Process #{Process.pid} was aborted"
|
85
85
|
end
|
86
86
|
end
|
87
87
|
end
|
@@ -93,10 +93,10 @@ void post_semaphore(char* name){
|
|
93
93
|
#pids.each do |pid| Process.waitpid pid end
|
94
94
|
|
95
95
|
rescue Exception
|
96
|
-
Log.
|
96
|
+
Log.warn "Killing children: #{pids.sort * ", " }"
|
97
97
|
pids.each do |pid| begin Process.kill("INT", pid); rescue; end; end
|
98
98
|
pids.each do |pid| begin RbbtSemaphore.post_semaphore(file); rescue; end; end
|
99
|
-
Log.
|
99
|
+
Log.warn "Ensuring children are dead: #{pids.sort * ", " }"
|
100
100
|
pids.each do |pid| begin Process.waitpid pid; rescue; end; end
|
101
101
|
end
|
102
102
|
end
|
@@ -46,7 +46,6 @@ class Step
|
|
46
46
|
begin
|
47
47
|
return @info_cache if @info_cache and File.mtime(info_file) < @info_cache_time
|
48
48
|
rescue Exception
|
49
|
-
Log.exception $!
|
50
49
|
raise $!
|
51
50
|
end
|
52
51
|
|
@@ -165,12 +164,18 @@ class Step
|
|
165
164
|
options = Misc.add_defaults options, :severity => Log::INFO
|
166
165
|
max = Misc.process_options options, :max
|
167
166
|
Log::ProgressBar.with_bar(max, options) do |bar|
|
168
|
-
|
167
|
+
begin
|
168
|
+
res = yield bar
|
169
|
+
raise KeepBar.new res if IO === res
|
170
|
+
res
|
171
|
+
rescue
|
172
|
+
Log.exception $!
|
173
|
+
end
|
169
174
|
end
|
170
175
|
end
|
171
176
|
|
172
177
|
def self.log(status, message, path, &block)
|
173
|
-
if
|
178
|
+
if block
|
174
179
|
if Hash === message
|
175
180
|
log_progress(status, message, path, &block)
|
176
181
|
else
|
@@ -202,7 +207,9 @@ class Step
|
|
202
207
|
def running?
|
203
208
|
return nil if not Open.exists? info_file
|
204
209
|
return nil if info[:pid].nil?
|
205
|
-
|
210
|
+
|
211
|
+
pid = @pid || info[:pid]
|
212
|
+
return Misc.pid_exists?(pid)
|
206
213
|
end
|
207
214
|
|
208
215
|
def error?
|
@@ -352,35 +359,48 @@ module Workflow
|
|
352
359
|
|
353
360
|
def rec_dependencies(taskname)
|
354
361
|
if task_dependencies.include? taskname
|
355
|
-
deps = task_dependencies[taskname].select{|dep| String === dep or Symbol === dep}
|
356
|
-
|
357
|
-
deps.
|
362
|
+
deps = task_dependencies[taskname].select{|dep| String === dep or Symbol === dep or Array === dep}
|
363
|
+
all_deps = deps.dup
|
364
|
+
deps.each do |dep|
|
365
|
+
if Array === dep
|
366
|
+
dep.first.rec_dependencies(dep.last).each do |d|
|
367
|
+
if Array === d
|
368
|
+
d
|
369
|
+
else
|
370
|
+
all_deps << [dep.first, d]
|
371
|
+
end
|
372
|
+
end
|
373
|
+
else
|
374
|
+
all_deps.concat rec_dependencies(dep.to_sym)
|
375
|
+
end
|
376
|
+
end
|
377
|
+
all_deps.uniq
|
358
378
|
else
|
359
379
|
[]
|
360
380
|
end
|
361
381
|
end
|
362
382
|
|
363
383
|
def rec_inputs(taskname)
|
364
|
-
[taskname].concat(rec_dependencies(taskname)).inject([]){|acc, tn| acc.concat tasks[tn.to_sym].inputs}
|
384
|
+
[taskname].concat(rec_dependencies(taskname)).inject([]){|acc, tn| acc.concat((Array === tn ? tn.first.tasks[tn.last] : tasks[tn.to_sym]).inputs) }
|
365
385
|
end
|
366
386
|
|
367
387
|
def rec_input_defaults(taskname)
|
368
|
-
[taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge tasks[tn.to_sym].input_defaults}.
|
388
|
+
[taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge((Array === tn ? tn.first.tasks[tn.last.to_sym] : tasks[tn.to_sym]).input_defaults) }.
|
369
389
|
tap{|h| IndiferentHash.setup(h)}
|
370
390
|
end
|
371
391
|
|
372
392
|
def rec_input_types(taskname)
|
373
|
-
[taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge tasks[tn.to_sym].input_types}.
|
393
|
+
[taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge((Array === tn ? tn.first.tasks[tn.last.to_sym] : tasks[tn.to_sym]).input_types) }.
|
374
394
|
tap{|h| IndiferentHash.setup(h) }
|
375
395
|
end
|
376
396
|
|
377
397
|
def rec_input_descriptions(taskname)
|
378
|
-
[taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge tasks[tn.to_sym].input_descriptions}.
|
398
|
+
[taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge((Array === tn ? tn.first.tasks[tn.last.to_sym] : tasks[tn.to_sym]).input_descriptions) }.
|
379
399
|
tap{|h| IndiferentHash.setup(h)}
|
380
400
|
end
|
381
401
|
|
382
402
|
def rec_input_options(taskname)
|
383
|
-
[taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge tasks[tn.to_sym].input_options}.
|
403
|
+
[taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge((Array === tn ? tn.first.tasks[tn.last.to_sym] : tasks[tn.to_sym]).input_options)}.
|
384
404
|
tap{|h| IndiferentHash.setup(h)}
|
385
405
|
end
|
386
406
|
|
@@ -388,6 +408,8 @@ module Workflow
|
|
388
408
|
real_dependencies = []
|
389
409
|
dependencies.each do |dependency|
|
390
410
|
real_dependencies << case dependency
|
411
|
+
when Array
|
412
|
+
dependency.first.job(dependency.last, jobname, inputs)
|
391
413
|
when Step
|
392
414
|
dependency
|
393
415
|
when Symbol
|
@@ -26,10 +26,14 @@ module Workflow
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def dep(*dependency_list, &block)
|
29
|
-
@dependency_list ||= []
|
30
29
|
@dependencies ||= []
|
31
|
-
dependency_list
|
32
|
-
|
30
|
+
if Array === dependency_list and Module === dependency_list.first
|
31
|
+
@dependencies << dependency_list
|
32
|
+
else
|
33
|
+
@dependency_list ||= []
|
34
|
+
dependency_list << block if block_given?
|
35
|
+
dependencies.concat dependency_list
|
36
|
+
end
|
33
37
|
end
|
34
38
|
|
35
39
|
def task(name, &block)
|
data/lib/rbbt/workflow/step.rb
CHANGED
@@ -47,7 +47,7 @@ class Step
|
|
47
47
|
end
|
48
48
|
|
49
49
|
class << self
|
50
|
-
|
50
|
+
attr_accessor :log_relay_step
|
51
51
|
end
|
52
52
|
|
53
53
|
def relay_log(step)
|
@@ -164,12 +164,13 @@ class Step
|
|
164
164
|
end
|
165
165
|
|
166
166
|
def recursive_clean
|
167
|
+
clean
|
167
168
|
rec_dependencies.each do |step|
|
168
|
-
if
|
169
|
+
if Open.exists?(step.info_file)
|
169
170
|
step.clean
|
171
|
+
else
|
170
172
|
end
|
171
173
|
end
|
172
|
-
clean
|
173
174
|
end
|
174
175
|
|
175
176
|
def step(name)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
class Step
|
2
2
|
|
3
|
-
attr_reader :stream
|
3
|
+
attr_reader :stream, :dupped
|
4
4
|
|
5
5
|
STREAM_CACHE = {}
|
6
6
|
STREAM_CACHE_MUTEX = Mutex.new
|
@@ -8,11 +8,28 @@ class Step
|
|
8
8
|
case stream
|
9
9
|
when IO, File
|
10
10
|
return stream if stream.closed?
|
11
|
+
|
11
12
|
STREAM_CACHE_MUTEX.synchronize do
|
12
|
-
|
13
|
+
case current = STREAM_CACHE[stream]
|
14
|
+
when nil
|
15
|
+
Log.medium "Not duplicating stream #{ Misc.fingerprint(stream) }"
|
13
16
|
STREAM_CACHE[stream] = stream
|
17
|
+
when File
|
18
|
+
if true or current.closed?
|
19
|
+
Log.medium "Reopening file #{ Misc.fingerprint(current) }"
|
20
|
+
Open.open(current.filename)
|
21
|
+
else
|
22
|
+
Log.medium "Duplicating file #{ Misc.fingerprint(current) }"
|
23
|
+
new = current.dup
|
24
|
+
new.rewind
|
25
|
+
new
|
26
|
+
end
|
27
|
+
|
14
28
|
else
|
15
|
-
Misc.
|
29
|
+
Log.medium "Duplicating stream #{ Misc.fingerprint(stream) }"
|
30
|
+
new = Misc.dup_stream(current)
|
31
|
+
Log.medium str << Log.color(:green, " -> ") << "#{new.inspect}"
|
32
|
+
new
|
16
33
|
end
|
17
34
|
end
|
18
35
|
when TSV::Dumper, TSV::Parser
|
@@ -21,9 +38,12 @@ class Step
|
|
21
38
|
|
22
39
|
STREAM_CACHE_MUTEX.synchronize do
|
23
40
|
if STREAM_CACHE[stream].nil?
|
41
|
+
Log.high "Not duplicating dumper #{ stream.inspect }"
|
24
42
|
STREAM_CACHE[stream] = stream
|
25
43
|
else
|
26
|
-
Misc.dup_stream(STREAM_CACHE[stream])
|
44
|
+
new = Misc.dup_stream(STREAM_CACHE[stream])
|
45
|
+
Log.high "Duplicating dumper #{ stream.inspect } into #{new.inspect}"
|
46
|
+
new
|
27
47
|
end
|
28
48
|
end
|
29
49
|
else
|
@@ -45,8 +65,12 @@ class Step
|
|
45
65
|
|
46
66
|
def get_stream
|
47
67
|
@mutex.synchronize do
|
48
|
-
|
49
|
-
IO === @result
|
68
|
+
begin
|
69
|
+
if IO === @result
|
70
|
+
@result
|
71
|
+
else
|
72
|
+
nil
|
73
|
+
end
|
50
74
|
ensure
|
51
75
|
@result = nil
|
52
76
|
end
|
@@ -54,20 +78,24 @@ class Step
|
|
54
78
|
end
|
55
79
|
|
56
80
|
def dup_inputs
|
57
|
-
@
|
81
|
+
return if @dupped or ENV["RBBT_NO_STREAM"] == 'true'
|
82
|
+
@inputs = @inputs.collect do |input|
|
58
83
|
Step.dup_stream input
|
59
84
|
end
|
85
|
+
@dupped = true
|
60
86
|
end
|
61
87
|
|
62
88
|
def _exec
|
63
89
|
@exec = true if @exec.nil?
|
64
|
-
@task.exec_in((bindings ? bindings : self),
|
90
|
+
@task.exec_in((bindings ? bindings : self), *@inputs)
|
65
91
|
end
|
66
92
|
|
67
93
|
def exec(no_load=false)
|
68
94
|
dependencies.each{|dependency| dependency.exec(no_load) }
|
69
|
-
@
|
70
|
-
|
95
|
+
@mutex.synchronize do
|
96
|
+
@result = self._exec
|
97
|
+
@result = @result.stream if TSV::Dumper === @result
|
98
|
+
end
|
71
99
|
no_load ? @result : prepare_result(@result, @task.result_description)
|
72
100
|
end
|
73
101
|
|
@@ -91,29 +119,50 @@ class Step
|
|
91
119
|
end
|
92
120
|
|
93
121
|
def run_dependencies(seen = [])
|
94
|
-
|
95
|
-
|
96
|
-
next if seen.include?
|
122
|
+
dependencies.uniq.each do |dependency|
|
123
|
+
|
124
|
+
next if seen.collect{|d| d.path}.include?(dependency.path)
|
125
|
+
seen << dependency
|
126
|
+
seen.concat dependency.rec_dependencies.collect{|d| d }
|
127
|
+
end
|
128
|
+
|
129
|
+
seen.each do |dependency|
|
130
|
+
next if dependency == self
|
131
|
+
dependency.relay_log self
|
132
|
+
dependency.dup_inputs
|
133
|
+
end
|
134
|
+
|
135
|
+
seen.each do |dependency|
|
136
|
+
next if dependency == self
|
97
137
|
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}"
|
98
138
|
begin
|
99
|
-
dependency.
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
139
|
+
if dependency.streaming?
|
140
|
+
next if dependency.running?
|
141
|
+
dependency.clean
|
142
|
+
else
|
143
|
+
dependency.clean if not dependency.done? and (dependency.error? or dependency.aborted?)
|
144
|
+
end
|
145
|
+
|
146
|
+
unless dependency.result or dependency.done?
|
147
|
+
dependency.run(true)
|
148
|
+
end
|
149
|
+
rescue Aborted, Interrupt
|
150
|
+
backtrace = $!.backtrace
|
151
|
+
set_info :backtrace, backtrace
|
152
|
+
log(:error, "Aborted dependency #{Log.color :yellow, dependency.task.name.to_s}")
|
153
|
+
raise $!
|
105
154
|
rescue Exception
|
106
155
|
backtrace = $!.backtrace
|
107
156
|
set_info :backtrace, backtrace
|
108
157
|
log(:error, "Exception processing dependency #{Log.color :yellow, dependency.task.name.to_s} -- #{$!.class}: #{$!.message}")
|
109
158
|
raise $!
|
110
159
|
end
|
111
|
-
|
160
|
+
end
|
112
161
|
end
|
113
162
|
|
114
163
|
def run(no_load = false)
|
115
|
-
|
116
164
|
result = nil
|
165
|
+
|
117
166
|
begin
|
118
167
|
@mutex.synchronize do
|
119
168
|
no_load = no_load ? :stream : false
|
@@ -131,7 +180,15 @@ class Step
|
|
131
180
|
log(:preparing, "Preparing job: #{Misc.fingerprint dependencies}")
|
132
181
|
set_info :dependencies, dependencies.collect{|dep| [dep.task_name, dep.name]}
|
133
182
|
|
134
|
-
|
183
|
+
dup_inputs
|
184
|
+
begin
|
185
|
+
run_dependencies
|
186
|
+
rescue
|
187
|
+
log(:error, "Error procesing dependencies")
|
188
|
+
stop_dependencies
|
189
|
+
raise $!
|
190
|
+
end
|
191
|
+
|
135
192
|
|
136
193
|
set_info :inputs, Misc.remove_long_items(Misc.zip2hash(task.inputs, @inputs)) unless task.inputs.nil?
|
137
194
|
|
@@ -192,7 +249,6 @@ class Step
|
|
192
249
|
log :streaming, "#{Log.color :magenta, "Streaming task result TSV::Dumper"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}]"
|
193
250
|
ConcurrentStream.setup result.stream do
|
194
251
|
begin
|
195
|
-
set_info :done, (done_time = Time.now)
|
196
252
|
set_info :done, (done_time = Time.now)
|
197
253
|
set_info :time_elapsed, (time_elapsed = done_time - start_time)
|
198
254
|
log :done, "#{Log.color :red, "Completed task"} #{Log.color :yellow, task.name.to_s || ""} [#{Process.pid}] +#{time_elapsed.to_i} -- #{path}"
|
@@ -284,7 +340,10 @@ class Step
|
|
284
340
|
|
285
341
|
def stop_dependencies
|
286
342
|
dependencies.each do |dep|
|
287
|
-
|
343
|
+
begin
|
344
|
+
dep.abort unless dep.done? or dep.error? or dep.aborted?
|
345
|
+
rescue Aborted
|
346
|
+
end
|
288
347
|
end
|
289
348
|
end
|
290
349
|
|
@@ -313,16 +372,23 @@ class Step
|
|
313
372
|
def abort_stream
|
314
373
|
stream = get_stream if @result
|
315
374
|
stream ||= @stream
|
316
|
-
if stream
|
317
|
-
|
375
|
+
if stream and stream.respond_to? :abort
|
376
|
+
Log.medium "Aborting stream #{stream.inspect} -- #{Log.color :blue, path}"
|
377
|
+
begin
|
378
|
+
stream.abort
|
379
|
+
rescue Aborted
|
380
|
+
end
|
318
381
|
end
|
319
382
|
end
|
320
383
|
|
321
384
|
def abort
|
385
|
+
Log.medium{"#{Log.color :red, "Aborting"} #{Log.color :blue, path}"}
|
322
386
|
begin
|
323
387
|
abort_pid
|
324
388
|
stop_dependencies
|
325
389
|
abort_stream
|
390
|
+
rescue
|
391
|
+
Log.exception $!
|
326
392
|
ensure
|
327
393
|
log(:aborted, "Job aborted")
|
328
394
|
end
|
@@ -333,7 +399,7 @@ class Step
|
|
333
399
|
if stream
|
334
400
|
begin
|
335
401
|
Misc.consume_stream stream
|
336
|
-
stream.join if stream.respond_to? :join
|
402
|
+
stream.join if stream.respond_to? :join
|
337
403
|
rescue Exception
|
338
404
|
stream.abort if stream.respond_to? :abort
|
339
405
|
self.abort
|
@@ -342,11 +408,16 @@ class Step
|
|
342
408
|
end
|
343
409
|
end
|
344
410
|
|
411
|
+
def grace
|
412
|
+
until done? or result or streaming? or error? or aborted?
|
413
|
+
sleep 1
|
414
|
+
end
|
415
|
+
self
|
416
|
+
end
|
417
|
+
|
345
418
|
def join
|
346
419
|
|
347
|
-
|
348
|
-
sleep 1
|
349
|
-
end
|
420
|
+
grace
|
350
421
|
|
351
422
|
join_stream if status == :streaming
|
352
423
|
|
@@ -362,6 +433,9 @@ class Step
|
|
362
433
|
begin
|
363
434
|
if pid.nil? or Process.pid == pid
|
364
435
|
dependencies.each{|dep| dep.join }
|
436
|
+
while not done?
|
437
|
+
sleep 1
|
438
|
+
end
|
365
439
|
else
|
366
440
|
begin
|
367
441
|
Log.debug{"Waiting for pid: #{pid}"}
|
data/lib/rbbt/workflow/usage.rb
CHANGED
@@ -71,7 +71,7 @@ module Workflow
|
|
71
71
|
task_name = task
|
72
72
|
task = self.tasks[task_name]
|
73
73
|
end
|
74
|
-
dependencies = self.rec_dependencies(task_name).collect{|dep_name| self.tasks[dep_name.to_sym]}
|
74
|
+
dependencies = self.rec_dependencies(task_name).collect{|dep_name| Array === dep_name ? dep_name.first.tasks[dep_name.last.to_sym] : self.tasks[dep_name.to_sym]}
|
75
75
|
|
76
76
|
task.doc(dependencies)
|
77
77
|
|
@@ -424,11 +424,21 @@ when Step
|
|
424
424
|
out.write block
|
425
425
|
end #unless io.closed?
|
426
426
|
io.join if io.respond_to? :join
|
427
|
+
rescue Aborted, Interrupt
|
428
|
+
Log.error "Process interrupted. Aborting step"
|
429
|
+
res.abort
|
430
|
+
begin
|
431
|
+
io.abort if io.respond_to? :abort
|
432
|
+
io.join if io.respond_to? :join
|
433
|
+
ensure
|
434
|
+
exit -1
|
435
|
+
end
|
427
436
|
rescue Exception
|
428
437
|
Log.exception $!
|
438
|
+
res.abort
|
429
439
|
begin
|
430
440
|
io.abort if io.respond_to? :abort
|
431
|
-
io.join
|
441
|
+
io.join if io.respond_to? :join
|
432
442
|
ensure
|
433
443
|
exit -1
|
434
444
|
end
|