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 +4 -4
- data/lib/rbbt/persist.rb +6 -4
- data/lib/rbbt/util/cmd.rb +2 -2
- data/lib/rbbt/util/concurrency/processes.rb +23 -15
- data/lib/rbbt/util/concurrency/processes/socket.rb +2 -2
- data/lib/rbbt/util/concurrency/processes/worker.rb +6 -2
- data/lib/rbbt/util/log.rb +3 -3
- data/lib/rbbt/util/log/progress.rb +4 -4
- data/lib/rbbt/util/log/progress/report.rb +79 -21
- data/lib/rbbt/util/misc/pipes.rb +2 -2
- data/lib/rbbt/util/open.rb +9 -1
- data/lib/rbbt/workflow/accessor.rb +15 -2
- data/lib/rbbt/workflow/step.rb +9 -0
- data/lib/rbbt/workflow/step/dependencies.rb +24 -17
- data/lib/rbbt/workflow/step/run.rb +182 -174
- data/test/rbbt/test_workflow.rb +6 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c7019b7a1b634937fbf75f958245dca674834f76
|
4
|
+
data.tar.gz: 7541763d2c390591b153b3d95c37277d63bdf6ea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
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
|
-
|
254
|
-
|
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
|
-
|
261
|
-
|
262
|
-
|
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 @
|
357
|
+
@callback_queue.clean if @callback_queue
|
350
358
|
end
|
351
359
|
end
|
352
360
|
|
@@ -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 =
|
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 =
|
141
|
-
"\
|
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 =
|
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
|
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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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 ||= [
|
77
|
+
@history ||= [[@ticks, Time.now] ]
|
27
78
|
else
|
28
|
-
@history <<
|
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
|
-
|
51
|
-
|
52
|
-
@history.
|
53
|
-
|
54
|
-
|
55
|
-
|
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
|
data/lib/rbbt/util/misc/pipes.rb
CHANGED
@@ -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
|
-
|
611
|
+
save, out = Misc.tee_stream stream
|
612
612
|
out.filename = file
|
613
613
|
save.filename = file
|
614
614
|
|
data/lib/rbbt/util/open.rb
CHANGED
@@ -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 !
|
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?
|
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
|
data/lib/rbbt/workflow/step.rb
CHANGED
@@ -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
|
-
|
84
|
-
job.
|
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.
|
90
|
-
|
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
|
-
|
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
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
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
|
-
|
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}]
|
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
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
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
|
-
|
192
|
+
Open.write(pid_file, Process.pid.to_s) unless Open.exists? pid_file
|
197
193
|
|
198
|
-
|
199
|
-
|
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
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
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
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
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
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
277
|
-
log :started, "Starting step #{Log.color :yellow, task.name.to_s || ""}"
|
264
|
+
@inputs = new_inputs if @inputs
|
278
265
|
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
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
|
-
|
297
|
-
|
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
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
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
|
-
|
309
|
-
|
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
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
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
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
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
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
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
|
-
|
356
|
+
ConcurrentStream.setup stream, :callback => callback, :abort_callback => abort_callback
|
356
357
|
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
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
|
-
|
375
|
+
set_info :dependencies, dependencies.collect{|dep| [dep.task_name, dep.name, dep.path]}
|
375
376
|
|
376
|
-
|
377
|
-
|
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
|
-
|
411
|
-
|
412
|
-
if
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
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
|
-
|
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) &&
|
673
|
+
end if File.exists?(info_file) && writable?
|
666
674
|
@result = nil
|
667
675
|
end
|
668
676
|
end
|
data/test/rbbt/test_workflow.rb
CHANGED
@@ -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
|
-
|
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.
|
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
|
+
date: 2018-08-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|