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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6ec4bc56a7d0d260d93be40ee61d23c08f58d5a8
4
- data.tar.gz: 6f51a747302e936ed1e5953e929e5120fa5caa89
3
+ metadata.gz: 2230976fc29ab61ab320c1c007521196acaa9b5f
4
+ data.tar.gz: 60ea71f47e8afa071cdc84f7de115487ec0b1ac5
5
5
  SHA512:
6
- metadata.gz: db5a97b2787f182444de536059beb027d038573c0c3ac3196ec44ce18d2561fa3204a38229d3054e5c92594309fc4a488cc6e9116e370c4f2d383b28a8ed9e71
7
- data.tar.gz: 8a4fc523ae9266ceea9964f26f85834a8f5c0e0899a523bb938e2e813da191651215ec356432ee7b467f39b470328b32dda911d1b2cd9bd757fa467ad14d54ce
6
+ metadata.gz: 8f7bbea5678b31d6f49ce13f94dd0b7d3271ae6e187ea837265e202ee90e95c3cb8af27ae5ba8c05b3dd8fa5d0d6eca14ae7870685990ae391fdfb1273ddbac8
7
+ data.tar.gz: d4746fa8d4393a9f7c399ae766b1881bc41568793ed50722a4b4f101a54962146fead34931b393c8ca44b3ea17057f59b21f505d7336939b777ede2983f9ddc9
@@ -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 != persist_options[:persist]
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 === :memory
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
- if callback
87
- TSV::Parser.traverse(io, options) do |k,v|
88
- res = yield k, v
89
- callback.call res
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
- else
92
- TSV::Parser.traverse(io, options, &block)
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)
@@ -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 join
9
-
33
+ def join_threads
10
34
  if @threads and @threads.any?
11
35
  @threads.each do |t|
12
- t.join unless t == Thread.current
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 abort
37
- @threads.each{|t| t.raise Aborted.new unless t = Thread.current } if @threads
38
- @threads.each{|t| t.join unless t = Thread.current } if @threads
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
- @pids.each{|pid| Process.waitpid pid } if @pids
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
@@ -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
@@ -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
- raise "Error writing in stream_in2" if skip2
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
- end
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
- def self._read_stream(stream, size)
217
- str = ""
218
- while (len=str.length) < size
219
- str << (stream.read(size-len) or break)
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
@@ -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
@@ -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 prepare_result(value, description = nil, info = {})
72
- case
73
- when IO === value
74
- begin
75
- case @task.result_type
76
- when :array
77
- array = []
78
- while line = value.gets
79
- array << line.strip
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
- 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
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 kill_children
178
- children_pids = info[:children_pids]
179
- if children_pids and children_pids.any?
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
- Process.kill "INT", pid
185
- rescue Exception
186
- Log.medium("Exception killing child #{ pid }: #{$!.message}")
187
- end
188
- end
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
- set_info :done, (done_time = Time.now)
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
- result
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
- RbbtSemaphore.post_semaphore(semaphore) if semaphore
90
+ value.join if value.respond_to? :join
91
+ value.close unless value.closed?
371
92
  end
372
- end
373
- set_info :forked, true
374
- Process.detach(@pid)
375
- self
376
- end
377
-
378
- def abort
379
- @pid ||= info[:pid]
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
- log(:aborted, "Job aborted")
399
- true
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
- io.abort if io.respond_to? :abort
417
- ensure
418
- io.join if io.respond_to? :join
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
@@ -75,6 +75,7 @@ class TestPersist < Test::Unit::TestCase
75
75
  end
76
76
 
77
77
  assert_equal 10, stream.read.split("\n").length
78
+ stream.join
78
79
  end
79
80
  end
80
81
  end
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.5
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