rbbt-util 5.23.14 → 5.23.15

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: 337b9a1997f89619b3fa00e0c79ff97104021dbc
4
- data.tar.gz: 0dfa5fda330f54920786ea1285bb1353f9a6b954
3
+ metadata.gz: c7019b7a1b634937fbf75f958245dca674834f76
4
+ data.tar.gz: 7541763d2c390591b153b3d95c37277d63bdf6ea
5
5
  SHA512:
6
- metadata.gz: 1ff6227b8954f15ea388a9bf39536146d5df3fa3ad38fe1d33285397baee097ece05409b2f35ab665066ad2097401341e7885cfc670ab63c2b4e6a03fc05519d
7
- data.tar.gz: beeec704c2efd2fbf361b1219a3545f41eb5a5d3ea41b7a4c2ec14006b11bab71603dab03c8a549d40bf3feedacb53cdfa3435f88828e9573dfe51ce6527baf0
6
+ metadata.gz: 86ac8dd6da1e81e8c9a801cda18728c736b91c4540c9a8d9b60b7c0e83885f3d501d290e19afea81392c0ebf57c96d50afb89f21ffc239ca47ba8cee3817d10f
7
+ data.tar.gz: 81afe72fbfd01c65c67722d71d58b0444a9e78ba178149a2ebc9a3f708fdc6e46937e751d6995ef499b248adb4a9355ad6fac4b1d4dfccd7fa6ab14fd89fd56a
data/lib/rbbt/persist.rb CHANGED
@@ -197,6 +197,9 @@ module Persist
197
197
  def self.tee_stream_thread(stream, path, type, callback = nil, abort_callback = nil, lockfile = nil)
198
198
  file, out = Misc.tee_stream(stream)
199
199
 
200
+ out.pair = file
201
+ file.pair = out
202
+
200
203
  saver_thread = Thread.new do
201
204
  begin
202
205
  file.threads = []
@@ -220,13 +223,12 @@ module Persist
220
223
  threads += stream.threads if stream.respond_to?(:threads) && stream.threads
221
224
  ConcurrentStream.setup(out, :threads => threads, :filename => path)
222
225
 
223
- out.callback = callback
226
+ #out.callback = callback
224
227
  out.abort_callback = abort_callback
225
228
  out.lockfile = stream.lockfile if stream.respond_to? :lockfile and stream.lockfile
226
229
 
227
- stream.callback = callback
228
- stream.abort_callback = abort_callback
229
-
230
+ #stream.callback = callback
231
+ #stream.abort_callback = abort_callback
230
232
 
231
233
  out
232
234
  end
data/lib/rbbt/util/cmd.rb CHANGED
@@ -138,7 +138,7 @@ module CMD
138
138
  if pipe
139
139
  err_thread = Thread.new do
140
140
  while line = serr.gets
141
- Log.log "STDERR [#{pid}]: " + line, stderr if Integer === stderr and log
141
+ Log.log "STDERR [#{pid}]: " + line, stderr if Integer === stderr and log
142
142
  end
143
143
  serr.close
144
144
  end
@@ -183,7 +183,7 @@ module CMD
183
183
  pid = io.pids.first
184
184
  while line = io.gets
185
185
  if pid
186
- Log.debug "STDOUT [#{pid}]: " + line
186
+ Log.debug "STDOUT [#{pid}]: " + line
187
187
  else
188
188
  Log.debug "STDOUT: " + line
189
189
  end
@@ -158,12 +158,17 @@ class RbbtProcessQueue
158
158
  begin
159
159
  while processes.any?
160
160
  raise Aborted if @abort_monitor
161
- processes[0].join
162
- Log.debug "Joined process #{processes[0].pid} of queue #{Process.pid}"
163
- processes.shift
161
+ #processes[0].join
162
+ #Log.debug "Joined process #{processes[0].pid} of queue #{Process.pid}"
163
+ #processes.shift
164
+ pid, status = Process.wait2
165
+ Log.debug "Joined process #{pid} of queue #{Process.pid} (status: #{status})"
166
+ processes.reject!{|p| p.pid == pid}
167
+ raise ProcessFailed.new pid if not status.success?
164
168
  end
165
169
  Log.low "All processes completed #{Process.pid}"
166
170
  rescue Aborted
171
+ Log.exception $!
167
172
  Log.low "Aborting process monitor #{Process.pid}"
168
173
  processes.each{|p| p.abort_and_join}
169
174
  Log.low "Processes aborted #{Process.pid}"
@@ -250,25 +255,28 @@ class RbbtProcessQueue
250
255
  begin
251
256
  pid, @status = Process.waitpid2 @master_pid unless @status
252
257
  error = true unless @status.success?
253
- raise ProcessFailed.new @master_pid unless @status.success?
254
- @callback_thread.join
258
+ begin
259
+ @callback_thread.join if @callback_thread
260
+ raise ProcessFailed.new @master_pid unless @status.success?
261
+ rescue
262
+ exception = $!
263
+ raise $!
264
+ end
255
265
  error = false
256
266
  rescue Aborted, Interrupt
257
267
  exception = $!
258
268
  Log.exception $!
259
269
  error = true
260
- self.abort
261
- Log.high "Process queue #{@master_pid} aborted"
262
- retry
270
+ if @aborted
271
+ raise $!
272
+ else
273
+ self.abort
274
+ Log.high "Process queue #{@master_pid} aborted"
275
+ retry
276
+ end
263
277
  rescue Errno::ESRCH, Errno::ECHILD
264
278
  retry if Misc.pid_exists? @master_pid
265
279
  error = ! @status.success?
266
- rescue ProcessFailed
267
- exception = $!
268
- rescue Exception
269
- exception = $!
270
- Log.exception $!
271
- retry
272
280
  ensure
273
281
  begin
274
282
  begin
@@ -346,7 +354,7 @@ class RbbtProcessQueue
346
354
  ensure
347
355
  @queue.clean if @queue
348
356
  #@callback_thread.push ClosedStream if @callback_thread && @callback_thread.alive?
349
- @callback_queue.clean if @queue
357
+ @callback_queue.clean if @callback_queue
350
358
  end
351
359
  end
352
360
 
@@ -78,11 +78,11 @@ class RbbtProcessQueue
78
78
  end
79
79
 
80
80
  def close_write
81
- @swrite.close
81
+ @swrite.close unless closed_write?
82
82
  end
83
83
 
84
84
  def close_read
85
- @sread.close
85
+ @sread.close unless closed_read?
86
86
  end
87
87
  #{{{ ACCESSOR
88
88
 
@@ -53,7 +53,6 @@ class RbbtProcessQueue
53
53
  break
54
54
  end
55
55
  end
56
- Kernel.exit! 0
57
56
  rescue Respawn
58
57
  Kernel.exit! 28
59
58
  rescue ClosedStream
@@ -63,6 +62,7 @@ class RbbtProcessQueue
63
62
  retry unless @stop
64
63
  Log.high "Worker #{Process.pid} leaving"
65
64
  rescue Exception
65
+ Log.high "Worker #{Process.pid} had exception: #{$!.message}"
66
66
  begin
67
67
  @callback_queue.push($!) if @callback_queue
68
68
  rescue
@@ -74,6 +74,8 @@ class RbbtProcessQueue
74
74
  rescue Aborted
75
75
  Log.high "Worker #{Process.pid} aborted"
76
76
  end
77
+
78
+ Log.high "Worker #{Process.pid} completed"
77
79
  Kernel.exit! 0
78
80
  end
79
81
 
@@ -92,7 +94,6 @@ class RbbtProcessQueue
92
94
 
93
95
  initial = Misc.memory_use(Process.pid)
94
96
  memory_cap = multiplier * initial
95
- Log.debug "Worker for #{Process.pid} started with pid #{@current} -- initial: #{initial} - multiplier: #{multiplier} - cap: #{memory_cap}"
96
97
 
97
98
  @asked = false
98
99
  @monitored = false
@@ -153,6 +154,8 @@ class RbbtProcessQueue
153
154
  run
154
155
  end
155
156
 
157
+ Log.debug "Worker for #{Process.pid} started with pid #{@current} -- initial: #{initial} - multiplier: #{multiplier} - cap: #{memory_cap}"
158
+
156
159
  while true
157
160
  @prev = @current
158
161
  pid, status = Process.waitpid2 @current
@@ -178,6 +181,7 @@ class RbbtProcessQueue
178
181
  end
179
182
 
180
183
  if status
184
+ Log.high "Worker respawner with #{Process.pid} (#{@current}) completed with status #{status}"
181
185
  Kernel.exit! status.to_i >> 8
182
186
  else
183
187
  Kernel.exit! -1
data/lib/rbbt/util/log.rb CHANGED
@@ -133,12 +133,12 @@ module Log
133
133
  end
134
134
  end
135
135
 
136
- def self.up_lines(num = 0)
136
+ def self.up_lines(num = 1)
137
137
  "\033[#{num+1}F\033[2K"
138
138
  end
139
139
 
140
- def self.down_lines(num = 0)
141
- "\n\033[#{num+2}E"
140
+ def self.down_lines(num = 1)
141
+ "\033[#{num+1}E"
142
142
  end
143
143
 
144
144
  def self.return_line
@@ -6,12 +6,12 @@ module Log
6
6
 
7
7
  attr_accessor :max, :ticks, :frequency, :depth, :desc, :file, :bytes
8
8
  def initialize(max = nil, options = {})
9
- options = Misc.add_defaults options, :depth => 0, :num_reports => 100, :desc => "Progress", :io => STDERR, :severity => Log.severity
10
- depth, num_reports, desc, io, severity, file, bytes = Misc.process_options options, :depth, :num_reports, :desc, :io, :severity, :file, :bytes
9
+ options = Misc.add_defaults options, :depth => 0, :num_reports => 100, :desc => "Progress", :io => STDERR, :severity => Log.severity, :frequency => 2
10
+ depth, num_reports, desc, io, severity, file, bytes, frequency = Misc.process_options options, :depth, :num_reports, :desc, :io, :severity, :file, :bytes, :frequency
11
11
 
12
12
  @max = max
13
13
  @ticks = 0
14
- @frequency = 2
14
+ @frequency = frequency
15
15
  @last_time = nil
16
16
  @last_count = nil
17
17
  @last_percent = nil
@@ -46,7 +46,7 @@ module Log
46
46
  end
47
47
 
48
48
  diff = time - @last_time
49
- report and return if diff > @frequency
49
+ report and return if diff >= @frequency
50
50
  return unless max and max > 0
51
51
 
52
52
  percent = self.percent
@@ -10,22 +10,73 @@ module Log
10
10
  end
11
11
 
12
12
  attr_accessor :history, :mean_max, :max_history
13
- def thr
14
- count = @ticks - @last_count
15
- if @last_time.nil?
16
- seconds = 0.001
17
- else
18
- seconds = Time.now - @last_time
19
- end
20
- thr = count / seconds
21
- end
13
+ #def thr
14
+ # count = (@ticks - @last_count).to_f
15
+ # if @last_time.nil?
16
+ # seconds = 0.001
17
+ # else
18
+ # seconds = Time.now - @last_time
19
+ # end
20
+ # thr = count / seconds
21
+ #end
22
+
23
+
24
+ #def thr_msg
25
+ # thr = self.thr
26
+ # if @history.nil?
27
+ # @history ||= [thr]
28
+ # else
29
+ # @history << thr
30
+ # max_history ||= case
31
+ # when @ticks > 20
32
+ # count = @ticks - @last_count
33
+ # if @max
34
+ # times = @max / count
35
+ # num = times / 20
36
+ # num = 2 if num < 2
37
+ # else
38
+ # num = 10
39
+ # end
40
+ # count * num
41
+ # else
42
+ # 20
43
+ # end
44
+ # max_history = 30 if max_history > 30
45
+ # max_history = 100
46
+ # @history.shift if @history.length > max_history
47
+ # end
48
+
49
+ # @mean_max ||= 0
50
+ # if @history.length > 3
51
+
52
+ # w_mean = 0
53
+ # total_w = 0
54
+ # @history.each_with_index do |v,i|
55
+ # c = i ** 10
56
+ # w_mean += v * c
57
+ # total_w += c
58
+ # end
59
+ # mean = @mean = w_mean.to_f / total_w
60
+
61
+ # @mean_max = mean if mean > @mean_max
62
+ # end
63
+
64
+ # if mean.nil? or mean.to_i > 1
65
+ # str = "#{ Log.color :blue, thr.to_i.to_s } per sec."
66
+ # str << " #{ Log.color :yellow, mean.to_i.to_s } avg. #{Log.color :yellow, @mean_max.to_i.to_s} max." if @mean_max > 0
67
+ # else
68
+ # str = "#{ Log.color :blue, (1/thr).ceil.to_s } secs each"
69
+ # str << " #{ Log.color :yellow, (1/mean).ceil.to_s } avg. #{Log.color :yellow, (1/@mean_max).ceil.to_s} min." if @mean_max > 0
70
+ # end
71
+
72
+ # str
73
+ #end
22
74
 
23
75
  def thr_msg
24
- thr = self.thr
25
76
  if @history.nil?
26
- @history ||= [thr]
77
+ @history ||= [[@ticks, Time.now] ]
27
78
  else
28
- @history << thr
79
+ @history << [@ticks, Time.now]
29
80
  max_history ||= case
30
81
  when @ticks > 20
31
82
  count = @ticks - @last_count
@@ -47,18 +98,23 @@ module Log
47
98
  @mean_max ||= 0
48
99
  if @history.length > 3
49
100
 
50
- w_mean = 0
51
- total_w = 0
52
- @history.each_with_index do |v,i|
53
- c = i ** 10
54
- w_mean += v * c
55
- total_w += c
56
- end
57
- mean = @mean = w_mean.to_f / total_w
101
+ sticks, stime = @history.first
102
+ ssticks, sstime = @history[3]
103
+ lticks, ltime = @history.last
104
+
105
+ mean = @mean = (lticks - sticks).to_f / (ltime - stime)
106
+ short_mean = (ssticks - sticks).to_f / (sstime - stime)
58
107
 
59
108
  @mean_max = mean if mean > @mean_max
60
109
  end
61
110
 
111
+ if short_mean
112
+ thr = short_mean
113
+ else
114
+ thr = @ticks / (Time.now - @start)
115
+ end
116
+ iii [short_mean, thr]
117
+
62
118
  if mean.nil? or mean.to_i > 1
63
119
  str = "#{ Log.color :blue, thr.to_i.to_s } per sec."
64
120
  str << " #{ Log.color :yellow, mean.to_i.to_s } avg. #{Log.color :yellow, @mean_max.to_i.to_s} max." if @mean_max > 0
@@ -70,6 +126,7 @@ module Log
70
126
  str
71
127
  end
72
128
 
129
+
73
130
  def eta_msg
74
131
  percent = self.percent
75
132
  time = Time.now
@@ -140,8 +197,9 @@ module Log
140
197
  else
141
198
  bars = BARS
142
199
  end
200
+ bars << self unless BARS.include? self
143
201
 
144
- print(io, Log.up_lines(bars.length) << Log.color(:yellow, "...Progress\n") << Log.down_lines(bars.length))
202
+ print(io, Log.up_lines(bars.length+1) << Log.color(:yellow, "...Progress\n") << Log.down_lines(bars.length+1))
145
203
  print(io, Log.up_lines(@depth) << report_msg << Log.down_lines(@depth))
146
204
  @last_time = Time.now
147
205
  @last_count = ticks
@@ -203,7 +203,7 @@ module Misc
203
203
  end
204
204
 
205
205
  stream.close unless stream.closed?
206
- stream.join if stream.respond_to? :join
206
+ #stream.join if stream.respond_to? :join
207
207
  in_pipes.first.close
208
208
  #Log.medium "Tee done #{Misc.fingerprint stream}"
209
209
  rescue Aborted, Interrupt
@@ -608,7 +608,7 @@ module Misc
608
608
  end
609
609
 
610
610
  def self.save_stream(file, stream)
611
- out, save = Misc.tee_stream stream
611
+ save, out = Misc.tee_stream stream
612
612
  out.filename = file
613
613
  save.filename = file
614
614
 
@@ -192,7 +192,7 @@ module Open
192
192
  if (dir_sub_path = find_repo_dir(file))
193
193
  remove_from_repo(*dir_sub_path)
194
194
  else
195
- FileUtils.rm(file)
195
+ FileUtils.rm(file) if File.exists?(file)
196
196
  end
197
197
  end
198
198
 
@@ -563,4 +563,12 @@ module Open
563
563
  end
564
564
  notify_write(file)
565
565
  end
566
+
567
+ def self.writable?(path)
568
+ if File.exists?(path)
569
+ File.writable?(path)
570
+ else
571
+ File.writable?(File.dirname(File.expand_path(path)))
572
+ end
573
+ end
566
574
  end
@@ -111,6 +111,14 @@ class Step
111
111
  @info_lock
112
112
  end
113
113
 
114
+ def status_lock
115
+ @status_lock = begin
116
+ path = Persist.persistence_path(info_file + '.status.lock', {:dir => Step.lock_dir})
117
+ Lockfile.new path, :refresh => false, :dont_use_lock_id => true
118
+ end if @status_lock.nil?
119
+ @status_lock
120
+ end
121
+
114
122
  def info(check_lock = true)
115
123
  return {:status => :noinfo} if info_file.nil? or not Open.exists? info_file
116
124
  begin
@@ -163,7 +171,7 @@ class Step
163
171
 
164
172
  def set_info(key, value)
165
173
  return nil if @exec or info_file.nil?
166
- return nil if ! File.writable? info_file
174
+ return nil if ! writable?
167
175
  value = Annotated.purge value if defined? Annotated
168
176
  Open.lock(info_file, :lock => info_lock) do
169
177
  i = info(false).dup
@@ -435,7 +443,7 @@ class Step
435
443
  end
436
444
 
437
445
  def stalled?
438
- started? && ! (done? || error? || aborted?) && ! running?
446
+ started? && ! (done? || error? || aborted? || running? || waiting?)
439
447
  end
440
448
 
441
449
  def missing?
@@ -626,6 +634,11 @@ class Step
626
634
  out
627
635
  end
628
636
  end
637
+
638
+ def relocated?
639
+ done? && info[:path] && info[:path] != path
640
+ end
641
+
629
642
  end
630
643
 
631
644
  module Workflow
@@ -273,6 +273,11 @@ class Step
273
273
  pid_file = Step.pid_file path
274
274
  files_dir = Step.files_dir path
275
275
 
276
+ if ! (Open.writable?(path) && Open.writable?(info_file))
277
+ Log.warn "Could not clean #{path}: not writable"
278
+ return
279
+ end
280
+
276
281
  if Open.exists?(path) or Open.exists?(pid_file) or Open.exists?(info_file) or Open.exists?(files_dir)
277
282
 
278
283
  @result = nil
@@ -324,6 +329,10 @@ class Step
324
329
  new_dependencies.uniq
325
330
  end
326
331
 
332
+ def writable?
333
+ Open.writable?(self.path) && Open.writable?(self.info_file)
334
+ end
335
+
327
336
  def recursive_clean
328
337
  dependencies.each do |step|
329
338
  step.recursive_clean
@@ -80,18 +80,23 @@ class Step
80
80
  return if status == 'streaming' and job.running?
81
81
  end
82
82
 
83
- if (status == 'error' && (job.recoverable_error? || job.dirty?)) ||
84
- job.aborted? ||
85
- (job.done? && ! job.updated?) || (job.error? && ! job.updated?) ||
86
- (job.done? && job.dirty?) || (job.error? && job.dirty?) ||
87
- (!(job.noinfo? || job.done? || job.error? || job.aborted? || job.running?))
83
+ job.status_lock.synchronize do
84
+ status = job.status.to_s
88
85
 
89
- job.clean
90
- end
86
+ if (status == 'error' && (job.recoverable_error? || job.dirty?)) ||
87
+ job.aborted? ||
88
+ (job.done? && ! job.updated?) || (job.error? && ! job.updated?) ||
89
+ (job.done? && job.dirty?) || (job.error? && job.dirty?) ||
90
+ (!(job.noinfo? || job.done? || job.error? || job.aborted? || job.running?))
91
+
92
+ job.clean
93
+ end
94
+
95
+ (job.init_info and job.dup_inputs) unless status == 'done' or job.started?
91
96
 
92
- (job.init_info and job.dup_inputs) unless status == 'done' or job.started?
97
+ canfail = ComputeDependency === job && job.canfail?
98
+ end
93
99
 
94
- canfail = ComputeDependency === job && job.canfail?
95
100
  raise DependencyError, job if job.error? and not canfail
96
101
  end
97
102
 
@@ -125,16 +130,18 @@ class Step
125
130
  return
126
131
  end
127
132
 
128
- if dependency.aborted? or (dependency.error? and dependency.recoverable_error?) or (!Open.remote?(dependency.path) && dependency.missing?)
129
- Log.warn "Cleaning dep. #{Log.color :red, dependency.task_name.to_s}"
130
- dependency.clean
131
- raise TryAgain
133
+ dependency.status_lock.synchronize do
134
+ if dependency.aborted? or (dependency.error? and dependency.recoverable_error?) or (!Open.remote?(dependency.path) && dependency.missing?)
135
+ Log.warn "Cleaning dep. on exec #{Log.color :blue, dependency.path} (missing: #{dependency.missing?}; error #{dependency.error?})"
136
+ dependency.clean
137
+ raise TryAgain
138
+ end
132
139
  end
133
140
 
134
141
  if ! dependency.started? && ! dependency.error?
135
142
  log_dependency_exec(dependency, :starting)
136
143
  dependency.run(true)
137
- raise TryAgain
144
+ raise TryAgain
138
145
  end
139
146
 
140
147
  dependency.grace
@@ -158,7 +165,7 @@ class Step
158
165
  end
159
166
 
160
167
  rescue TryAgain
161
- Log.low "Retrying dep. #{Log.color :yellow, dependency.task_name.to_s} -- [#{dependency.status}] #{(dependency.messages || ["No message"]).last}"
168
+ Log.low "Retrying dep. #{Log.color :yellow, dependency.task_name.to_s} -- [#{dependency.status}] #{(dependency.messages || ["No message"]).last}"
162
169
  retry
163
170
  rescue Aborted, Interrupt
164
171
  Log.error "Aborted dep. #{Log.color :red, dependency.task_name.to_s}"
@@ -417,8 +424,8 @@ class Step
417
424
  dangling_deps = all_deps.reject{|dep| dep.done? || canfail_paths.include?(dep.path) }.
418
425
  select{|dep| dep.waiting? }
419
426
 
420
- Log.medium "Aborting waiting dangling dependencies #{Misc.fingerprint dangling_deps}" if dangling_deps.any?
421
- dangling_deps.each{|dep| dep.abort }
427
+ Log.medium "Aborting (actually not) waiting dangling dependencies #{Misc.fingerprint dangling_deps}" if dangling_deps.any?
428
+ #dangling_deps.each{|dep| dep.abort }
422
429
 
423
430
  end
424
431
 
@@ -108,7 +108,7 @@ class Step
108
108
  rec_dependencies.
109
109
  select{|dependency| ! (defined? WorkflowRESTClient and WorkflowRESTClient::RemoteStep === dependency) }.
110
110
  select{|dependency| ! Open.remote?(dependency.path) }.
111
- select{|dependency| Open.exists?(dependency.info_file) }.
111
+ select{|dependency| Open.exists?(dependency.info_file) && ! dependency.relocated? }.
112
112
  select{|dependency| ! dependency.error? }
113
113
  end
114
114
 
@@ -120,7 +120,6 @@ class Step
120
120
  (dependency_checks + input_checks).uniq
121
121
  end
122
122
 
123
-
124
123
  def out_of_date
125
124
 
126
125
  checks = self.checks
@@ -130,6 +129,7 @@ class Step
130
129
  canfail_paths = self.canfail_paths
131
130
  checks.each do |dep|
132
131
  next unless Open.exists?(dep.info_file)
132
+ next if dep.relocated?
133
133
 
134
134
  begin
135
135
  if dep.done? && self.done? && Open.exists?(dep.path) && Open.exists?(self.path) && (File.mtime(dep.path) > File.mtime(self.path))
@@ -150,7 +150,7 @@ class Step
150
150
  end
151
151
 
152
152
  def updated?
153
- return true unless (done? || error?)
153
+ return true unless (done? || error? || ! writable?)
154
154
 
155
155
  @updated ||= out_of_date.empty?
156
156
  end
@@ -182,201 +182,203 @@ class Step
182
182
  res = @mutex.synchronize do
183
183
  no_load = :stream if no_load
184
184
 
185
- Open.write(pid_file, Process.pid.to_s) unless Open.exists?(path) or Open.exists?(pid_file)
186
- result = Persist.persist "Job", @task.result_type, :file => path, :check => checks.collect{|dep| dep.path}, :no_load => no_load do
187
- if Step === Step.log_relay_step and not self == Step.log_relay_step
188
- relay_log(Step.log_relay_step) unless self.respond_to? :relay_step and self.relay_step
189
- end
190
-
191
- Open.write(pid_file, Process.pid.to_s) unless Open.exists? pid_file
192
-
193
- @exec = false
194
- init_info
185
+ self.status_lock.synchronize do
186
+ Open.write(pid_file, Process.pid.to_s) unless Open.exists?(path) or Open.exists?(pid_file)
187
+ result = Persist.persist "Job", @task.result_type, :file => path, :check => checks.collect{|dep| dep.path}, :no_load => no_load do
188
+ if Step === Step.log_relay_step and not self == Step.log_relay_step
189
+ relay_log(Step.log_relay_step) unless self.respond_to? :relay_step and self.relay_step
190
+ end
195
191
 
196
- log :setup, "#{Log.color :green, "Setup"} step #{Log.color :yellow, task.name.to_s || ""}"
192
+ Open.write(pid_file, Process.pid.to_s) unless Open.exists? pid_file
197
193
 
198
- merge_info({
199
- :issued => (issue_time = Time.now),
200
- :name => name,
201
- :clean_name => clean_name,
202
- :workflow => (@workflow || @task.workflow).to_s,
203
- :task_name => @task.name,
204
- :result_type => @task.result_type,
205
- :result_description => @task.result_description,
206
- :dependencies => dependencies.collect{|dep| [dep.task_name, dep.name, dep.path]}
207
- })
194
+ @exec = false
195
+ init_info
208
196
 
197
+ log :setup, "#{Log.color :green, "Setup"} step #{Log.color :yellow, task.name.to_s || ""}"
209
198
 
210
- begin
211
- run_dependencies
212
- rescue Exception
213
- FileUtils.rm pid_file if File.exist?(pid_file)
214
- stop_dependencies
215
- raise $!
216
- end
199
+ merge_info({
200
+ :issued => (issue_time = Time.now),
201
+ :name => name,
202
+ :clean_name => clean_name,
203
+ :workflow => (@workflow || @task.workflow).to_s,
204
+ :task_name => @task.name,
205
+ :result_type => @task.result_type,
206
+ :result_description => @task.result_description,
207
+ :dependencies => dependencies.collect{|dep| [dep.task_name, dep.name, dep.path]}
208
+ })
217
209
 
218
- new_inputs = []
219
- @inputs.each_with_index do |input,i|
220
- name = @task.inputs[i]
221
- type = @task.input_types[name]
222
210
 
223
- if type == :directory
224
- directory_inputs = file('directory_inputs')
225
- input_source = directory_inputs['.source'][name].find
226
- input_dir = directory_inputs[name].find
211
+ begin
212
+ run_dependencies
213
+ rescue Exception
214
+ FileUtils.rm pid_file if File.exist?(pid_file)
215
+ stop_dependencies
216
+ raise $!
217
+ end
227
218
 
228
- case input
229
- when Path
230
- if input.directory?
231
- new_inputs << input
232
- else
233
- input.open do |io|
234
- begin
235
- Misc.untar(io, input_source)
236
- rescue
237
- raise ParameterException, "Error unpackaging tar directory input '#{name}':\n\n#{$!.message}"
219
+ new_inputs = []
220
+ @inputs.each_with_index do |input,i|
221
+ name = @task.inputs[i]
222
+ type = @task.input_types[name]
223
+
224
+ if type == :directory
225
+ directory_inputs = file('directory_inputs')
226
+ input_source = directory_inputs['.source'][name].find
227
+ input_dir = directory_inputs[name].find
228
+
229
+ case input
230
+ when Path
231
+ if input.directory?
232
+ new_inputs << input
233
+ else
234
+ input.open do |io|
235
+ begin
236
+ Misc.untar(io, input_source)
237
+ rescue
238
+ raise ParameterException, "Error unpackaging tar directory input '#{name}':\n\n#{$!.message}"
239
+ end
238
240
  end
241
+ tar_1 = input_source.glob("*")
242
+ raise ParameterException, "When using tar.gz files for directories, the directory must be the single first level entry" if tar_1.length != 1
243
+ FileUtils.ln_s Misc.path_relative_to(directory_inputs, tar_1.first), input_dir
244
+ new_inputs << input_dir
245
+ end
246
+ when File, IO, Tempfile
247
+ begin
248
+ Misc.untar(Open.gunzip(input), input_source)
249
+ rescue
250
+ raise ParameterException, "Error unpackaging tar directory input '#{name}':\n\n#{$!.message}"
239
251
  end
240
252
  tar_1 = input_source.glob("*")
241
253
  raise ParameterException, "When using tar.gz files for directories, the directory must be the single first level entry" if tar_1.length != 1
242
- FileUtils.ln_s Misc.path_relative_to(directory_inputs, tar_1.first), input_dir
254
+ FileUtils.ln_s Misc.path_relative_to(directory_inputs, tar_1.first), input_dir
243
255
  new_inputs << input_dir
256
+ else
257
+ raise ParameterException, "Format of directory input '#{name}' not understood: #{Misc.fingerprint input}"
244
258
  end
245
- when File, IO, Tempfile
246
- begin
247
- Misc.untar(Open.gunzip(input), input_source)
248
- rescue
249
- raise ParameterException, "Error unpackaging tar directory input '#{name}':\n\n#{$!.message}"
250
- end
251
- tar_1 = input_source.glob("*")
252
- raise ParameterException, "When using tar.gz files for directories, the directory must be the single first level entry" if tar_1.length != 1
253
- FileUtils.ln_s Misc.path_relative_to(directory_inputs, tar_1.first), input_dir
254
- new_inputs << input_dir
255
259
  else
256
- raise ParameterException, "Format of directory input '#{name}' not understood: #{Misc.fingerprint input}"
257
- end
258
- else
259
- new_inputs << input
260
- end
261
- end if @inputs
262
-
263
- @inputs = new_inputs if @inputs
264
-
265
- if not task.inputs.nil?
266
- info_inputs = @inputs.collect do |i|
267
- if Path === i
268
- i.to_s
269
- else
270
- i
260
+ new_inputs << input
271
261
  end
272
- end
273
- set_info :inputs, Misc.remove_long_items(Misc.zip2hash(task.inputs, info_inputs))
274
- end
262
+ end if @inputs
275
263
 
276
- set_info :started, (start_time = Time.now)
277
- log :started, "Starting step #{Log.color :yellow, task.name.to_s || ""}"
264
+ @inputs = new_inputs if @inputs
278
265
 
279
- begin
280
- result = _exec
281
- rescue Aborted, Interrupt
282
- log(:aborted, "Aborted")
283
- raise $!
284
- rescue Exception
285
- backtrace = $!.backtrace
286
-
287
- # HACK: This fixes an strange behaviour in 1.9.3 where some
288
- # backtrace strings are coded in ASCII-8BIT
289
- backtrace.each{|l| l.force_encoding("UTF-8")} if String.instance_methods.include? :force_encoding
290
- set_info :backtrace, backtrace
291
- log(:error, "#{$!.class}: #{$!.message}")
292
- stop_dependencies
293
- raise $!
294
- end
266
+ if not task.inputs.nil?
267
+ info_inputs = @inputs.collect do |i|
268
+ if Path === i
269
+ i.to_s
270
+ else
271
+ i
272
+ end
273
+ end
274
+ set_info :inputs, Misc.remove_long_items(Misc.zip2hash(task.inputs, info_inputs))
275
+ end
295
276
 
296
- if not no_load or ENV["RBBT_NO_STREAM"] == "true"
297
- result = prepare_result result, @task.description, info if IO === result
298
- result = prepare_result result.stream, @task.description, info if TSV::Dumper === result
299
- end
277
+ set_info :started, (start_time = Time.now)
278
+ log :started, "Starting step #{Log.color :yellow, task.name.to_s || ""}"
300
279
 
301
- stream = case result
302
- when IO
303
- result
304
- when TSV::Dumper
305
- result.stream
306
- end
280
+ begin
281
+ result = _exec
282
+ rescue Aborted, Interrupt
283
+ log(:aborted, "Aborted")
284
+ raise $!
285
+ rescue Exception
286
+ backtrace = $!.backtrace
287
+
288
+ # HACK: This fixes an strange behaviour in 1.9.3 where some
289
+ # backtrace strings are coded in ASCII-8BIT
290
+ backtrace.each{|l| l.force_encoding("UTF-8")} if String.instance_methods.include? :force_encoding
291
+ set_info :backtrace, backtrace
292
+ log(:error, "#{$!.class}: #{$!.message}")
293
+ stop_dependencies
294
+ raise $!
295
+ end
307
296
 
308
- if stream
309
- log :streaming, "Streaming step #{Log.color :yellow, task.name.to_s || ""}"
297
+ if not no_load or ENV["RBBT_NO_STREAM"] == "true"
298
+ result = prepare_result result, @task.description, info if IO === result
299
+ result = prepare_result result.stream, @task.description, info if TSV::Dumper === result
300
+ end
310
301
 
311
- callback = Proc.new do
312
- if AbortedStream === stream
313
- if stream.exception
314
- raise stream.exception
315
- else
316
- raise Aborted
302
+ stream = case result
303
+ when IO
304
+ result
305
+ when TSV::Dumper
306
+ result.stream
307
+ end
308
+
309
+ if stream
310
+ log :streaming, "Streaming step #{Log.color :yellow, task.name.to_s || ""}"
311
+
312
+ callback = Proc.new do
313
+ if AbortedStream === stream
314
+ if stream.exception
315
+ raise stream.exception
316
+ else
317
+ raise Aborted
318
+ end
317
319
  end
318
- end
319
- begin
320
- status = self.status
321
- if status != :done and status != :error and status != :aborted
322
- Misc.insist do
323
- merge_info({
324
- :done => (done_time = Time.now),
325
- :total_time_elapsed => (total_time_elapsed = done_time - issue_time),
326
- :time_elapsed => (time_elapsed = done_time - start_time)
327
- })
328
- log :done, "Completed step #{Log.color :yellow, task.name.to_s || ""} in #{time_elapsed.to_i}+#{(total_time_elapsed - time_elapsed).to_i} sec."
320
+ begin
321
+ status = self.status
322
+ if status != :done and status != :error and status != :aborted
323
+ Misc.insist do
324
+ merge_info({
325
+ :done => (done_time = Time.now),
326
+ :total_time_elapsed => (total_time_elapsed = done_time - issue_time),
327
+ :time_elapsed => (time_elapsed = done_time - start_time)
328
+ })
329
+ log :done, "Completed step #{Log.color :yellow, task.name.to_s || ""} in #{time_elapsed.to_i}+#{(total_time_elapsed - time_elapsed).to_i} sec."
330
+ end
329
331
  end
332
+ rescue
333
+ Log.exception $!
334
+ ensure
335
+ Step.purge_stream_cache
336
+ set_info :pid, nil
337
+ FileUtils.rm pid_file if File.exist?(pid_file)
330
338
  end
331
- rescue
332
- Log.exception $!
333
- ensure
334
- Step.purge_stream_cache
335
- set_info :pid, nil
336
- FileUtils.rm pid_file if File.exist?(pid_file)
337
339
  end
338
- end
339
340
 
340
- abort_callback = Proc.new do |exception|
341
- begin
342
- if exception
343
- self.exception exception
344
- else
345
- log :aborted, "#{Log.color :red, "Aborted"} step #{Log.color :yellow, task.name.to_s || ""}" if status == :streaming
341
+ abort_callback = Proc.new do |exception|
342
+ begin
343
+ if exception
344
+ self.exception exception
345
+ else
346
+ log :aborted, "#{Log.color :red, "Aborted"} step #{Log.color :yellow, task.name.to_s || ""}" if status == :streaming
347
+ end
348
+ _clean_finished
349
+ rescue
350
+ stop_dependencies
351
+ set_info :pid, nil
352
+ FileUtils.rm pid_file if File.exist?(pid_file)
346
353
  end
347
- _clean_finished
348
- rescue
349
- stop_dependencies
350
- set_info :pid, nil
351
- FileUtils.rm pid_file if File.exist?(pid_file)
352
354
  end
353
- end
354
355
 
355
- ConcurrentStream.setup stream, :callback => callback, :abort_callback => abort_callback
356
+ ConcurrentStream.setup stream, :callback => callback, :abort_callback => abort_callback
356
357
 
357
- if AbortedStream === stream
358
- exception = stream.exception || Aborted.new("Aborted stream: #{Misc.fingerprint stream}")
359
- self.exception exception
360
- _clean_finished
361
- raise exception
358
+ if AbortedStream === stream
359
+ exception = stream.exception || Aborted.new("Aborted stream: #{Misc.fingerprint stream}")
360
+ self.exception exception
361
+ _clean_finished
362
+ raise exception
363
+ end
364
+ else
365
+ merge_info({
366
+ :done => (done_time = Time.now),
367
+ :total_time_elapsed => (total_time_elapsed = done_time - issue_time),
368
+ :time_elapsed => (time_elapsed = done_time - start_time)
369
+ })
370
+ log :ending
371
+ Step.purge_stream_cache
372
+ FileUtils.rm pid_file if File.exist?(pid_file)
362
373
  end
363
- else
364
- merge_info({
365
- :done => (done_time = Time.now),
366
- :total_time_elapsed => (total_time_elapsed = done_time - issue_time),
367
- :time_elapsed => (time_elapsed = done_time - start_time)
368
- })
369
- log :ending
370
- Step.purge_stream_cache
371
- FileUtils.rm pid_file if File.exist?(pid_file)
372
- end
373
374
 
374
- set_info :dependencies, dependencies.collect{|dep| [dep.task_name, dep.name, dep.path]}
375
+ set_info :dependencies, dependencies.collect{|dep| [dep.task_name, dep.name, dep.path]}
375
376
 
376
- if result.nil? && File.exists?(self.tmp_path) && ! File.exists?(self.path)
377
- FileUtils.mv self.tmp_path, self.path
377
+ if result.nil? && File.exists?(self.tmp_path) && ! File.exists?(self.path)
378
+ FileUtils.mv self.tmp_path, self.path
379
+ end
380
+ result
378
381
  end
379
- result
380
382
  end
381
383
 
382
384
  if no_load
@@ -407,16 +409,22 @@ class Step
407
409
  def produce(force=false, dofork=false)
408
410
  return self if done? and not dirty?
409
411
 
410
- if error? or aborted? or stalled?
411
- abort if stalled?
412
- if force or aborted? or recoverable_error?
413
- clean
414
- else
415
- e = get_exception
416
- if e
417
- raise e
412
+
413
+ self.status_lock.synchronize do
414
+ if error? or aborted? or stalled?
415
+ if stalled?
416
+ Log.warn "Aborting stalled job #{self.path}"
417
+ abort
418
+ end
419
+ if force or aborted? or recoverable_error?
420
+ clean
418
421
  else
419
- raise "Error in job: #{self.path}"
422
+ e = get_exception
423
+ if e
424
+ raise e
425
+ else
426
+ raise "Error in job: #{self.path}"
427
+ end
420
428
  end
421
429
  end
422
430
  end
@@ -662,7 +670,7 @@ class Step
662
670
  begin
663
671
  set_info :joined, true
664
672
  rescue
665
- end if File.exists?(info_file) && File.writable?(info_file)
673
+ end if File.exists?(info_file) && writable?
666
674
  @result = nil
667
675
  end
668
676
  end
@@ -146,18 +146,22 @@ class TestWorkflow < Test::Unit::TestCase
146
146
  end
147
147
 
148
148
  def test_update_on_input_dependency_update
149
+ Log.severity = 0
149
150
  send_input_dep_to_reverse_job = TestWF.job(:send_input_dep_to_reverse, nil, :name => "Miguel")
150
151
  send_input_dep_to_reverse_job.clean
151
152
  send_input_dep_to_reverse_job.run
153
+
152
154
  input_dep_job = send_input_dep_to_reverse_job.step(:input_dep)
155
+ mtime_orig = File.mtime send_input_dep_to_reverse_job.step(:reverse_input_text).path
156
+
157
+ sleep 1
153
158
  input_dep_job.clean
154
159
  input_dep_job.run
155
160
  send_input_dep_to_reverse_job = TestWF.job(:send_input_dep_to_reverse, nil, :name => "Miguel")
156
- mtime_orig = File.mtime send_input_dep_to_reverse_job.step(:reverse_input_text).path
161
+
157
162
  send_input_dep_to_reverse_job.run
158
163
  mtime_new = File.mtime send_input_dep_to_reverse_job.step(:reverse_input_text).path
159
164
  assert mtime_orig < mtime_new
160
-
161
165
  end
162
166
 
163
167
  def test_helper
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbbt-util
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.23.14
4
+ version: 5.23.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miguel Vazquez
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-08-11 00:00:00.000000000 Z
11
+ date: 2018-08-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake