rbbt-util 5.13.1 → 5.13.2
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 +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
|