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.
@@ -81,7 +81,7 @@ void post_semaphore(char* name){
81
81
  yield elem
82
82
  end
83
83
  rescue Interrupt
84
- Log.error "Process #{Process.pid} was aborted"
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.error "Killing children: #{pids.sort * ", " }"
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.error "Ensuring children are dead: #{pids.sort * ", " }"
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
- yield bar
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 block_given?
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
- return Misc.pid_exists?(p = info[:pid]) && Process.pid != p
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
- deps.concat deps.collect{|dep| rec_dependencies(dep)}.flatten
357
- deps.uniq
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 << block if block_given?
32
- dependencies.concat dependency_list
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)
@@ -47,7 +47,7 @@ class Step
47
47
  end
48
48
 
49
49
  class << self
50
- attr_accessor :log_relay_step
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 File.exists?(step.info_file)
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
- if STREAM_CACHE[stream].nil?
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.dup_stream(STREAM_CACHE[stream])
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
- @stream = begin
49
- IO === @result ? @result : nil
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
- @inputs.collect do |input|
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), *dup_inputs)
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
- @result = self._exec
70
- @result = @result.stream if TSV::Dumper === @result
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
- seen << self.path
95
- dependencies.uniq.each{|dependency|
96
- next if seen.include? dependency.path
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.relay_log self
100
- dependency.clean if not dependency.done? and (dependency.error? or dependency.aborted?)
101
- dependency.clean if dependency.streaming? and not dependency.running?
102
- dependency.run(ENV["RBBT_NO_STREAM"] != 'true') unless dependency.result or dependency.done?
103
- seen << dependency.path
104
- seen.concat dependency.rec_dependencies.collect{|d| d.path}
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
- run_dependencies
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
- dep.abort unless dep.done?
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
- stream.abort if stream.respond_to? :abort
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 # and not stream.joined?
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
- until done? or result or error? or aborted? or streaming?
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}"}
@@ -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