rbbt-util 5.23.14 → 5.23.15

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 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