scout-gear 10.11.4 → 10.11.7
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 +4 -4
- data/.vimproject +17 -2
- data/VERSION +1 -1
- data/bin/scout +10 -10
- data/lib/scout/association/fields.rb +15 -15
- data/lib/scout/association/index.rb +6 -6
- data/lib/scout/association/item.rb +18 -8
- data/lib/scout/association.rb +4 -4
- data/lib/scout/entity/identifiers.rb +5 -5
- data/lib/scout/entity/property.rb +2 -2
- data/lib/scout/entity.rb +1 -1
- data/lib/scout/knowledge_base/description.rb +10 -10
- data/lib/scout/knowledge_base/entity.rb +6 -6
- data/lib/scout/knowledge_base/list.rb +1 -1
- data/lib/scout/knowledge_base/query.rb +4 -4
- data/lib/scout/knowledge_base/registry.rb +6 -6
- data/lib/scout/knowledge_base/traverse.rb +7 -40
- data/lib/scout/persist/engine/fix_width_table.rb +6 -6
- data/lib/scout/persist/engine/packed_index.rb +2 -2
- data/lib/scout/persist/engine/sharder.rb +4 -4
- data/lib/scout/persist/engine/tkrzw.rb +1 -1
- data/lib/scout/persist/engine/tokyocabinet.rb +2 -2
- data/lib/scout/persist/tsv/adapter/fix_width_table.rb +1 -1
- data/lib/scout/persist/tsv/adapter/packed_index.rb +1 -1
- data/lib/scout/persist/tsv/adapter/tkrzw.rb +1 -1
- data/lib/scout/persist/tsv/adapter/tokyocabinet.rb +3 -3
- data/lib/scout/persist/tsv/serialize.rb +3 -3
- data/lib/scout/persist/tsv.rb +1 -1
- data/lib/scout/semaphore.rb +100 -17
- data/lib/scout/tsv/annotation/repo.rb +4 -4
- data/lib/scout/tsv/annotation.rb +2 -2
- data/lib/scout/tsv/attach.rb +7 -7
- data/lib/scout/tsv/change_id/translate.rb +1 -1
- data/lib/scout/tsv/csv.rb +3 -3
- data/lib/scout/tsv/dumper.rb +8 -8
- data/lib/scout/tsv/index.rb +1 -1
- data/lib/scout/tsv/open.rb +3 -3
- data/lib/scout/tsv/stream.rb +2 -2
- data/lib/scout/tsv/traverse.rb +4 -4
- data/lib/scout/tsv/util/filter.rb +9 -9
- data/lib/scout/tsv/util/process.rb +2 -2
- data/lib/scout/tsv/util/reorder.rb +2 -2
- data/lib/scout/tsv/util/select.rb +3 -3
- data/lib/scout/tsv/util/unzip.rb +2 -2
- data/lib/scout/tsv/util.rb +1 -1
- data/lib/scout/tsv.rb +2 -2
- data/lib/scout/work_queue/socket.rb +3 -2
- data/lib/scout/work_queue/worker.rb +4 -4
- data/lib/scout/work_queue.rb +7 -7
- data/lib/scout/workflow/definition.rb +18 -16
- data/lib/scout/workflow/deployment/local.rb +81 -62
- data/lib/scout/workflow/deployment/orchestrator/batches.rb +66 -5
- data/lib/scout/workflow/deployment/orchestrator/chains.rb +47 -30
- data/lib/scout/workflow/deployment/orchestrator/rules.rb +3 -3
- data/lib/scout/workflow/deployment/orchestrator/workload.rb +11 -22
- data/lib/scout/workflow/deployment/scheduler/job.rb +34 -36
- data/lib/scout/workflow/deployment/scheduler/lfs.rb +1 -1
- data/lib/scout/workflow/deployment/scheduler/pbs.rb +4 -4
- data/lib/scout/workflow/deployment/scheduler/slurm.rb +2 -2
- data/lib/scout/workflow/deployment/scheduler.rb +23 -12
- data/lib/scout/workflow/deployment/trace.rb +2 -2
- data/lib/scout/workflow/documentation.rb +4 -4
- data/lib/scout/workflow/export.rb +1 -1
- data/lib/scout/workflow/path.rb +2 -2
- data/lib/scout/workflow/step/children.rb +1 -1
- data/lib/scout/workflow/step/dependencies.rb +36 -3
- data/lib/scout/workflow/step/info.rb +5 -19
- data/lib/scout/workflow/step/inputs.rb +1 -1
- data/lib/scout/workflow/step/progress.rb +2 -2
- data/lib/scout/workflow/step/provenance.rb +4 -4
- data/lib/scout/workflow/step/status.rb +23 -9
- data/lib/scout/workflow/step.rb +21 -19
- data/lib/scout/workflow/task/dependencies.rb +10 -3
- data/lib/scout/workflow/task/info.rb +3 -3
- data/lib/scout/workflow/task/inputs.rb +8 -8
- data/lib/scout/workflow/task.rb +37 -22
- data/lib/scout/workflow/usage.rb +13 -13
- data/lib/scout/workflow/util.rb +1 -1
- data/lib/scout/workflow.rb +6 -6
- data/scout-gear.gemspec +4 -3
- data/scout_commands/alias +1 -1
- data/scout_commands/batch/clean +12 -12
- data/scout_commands/batch/list +26 -25
- data/scout_commands/batch/tail +9 -5
- data/scout_commands/cat +1 -1
- data/scout_commands/doc +2 -2
- data/scout_commands/entity +4 -4
- data/scout_commands/find +1 -1
- data/scout_commands/kb/config +1 -1
- data/scout_commands/kb/entities +1 -1
- data/scout_commands/kb/list +1 -1
- data/scout_commands/kb/query +2 -2
- data/scout_commands/kb/register +1 -1
- data/scout_commands/kb/show +1 -1
- data/scout_commands/kb/traverse +1 -1
- data/scout_commands/log +6 -6
- data/scout_commands/resource/produce +2 -2
- data/scout_commands/resource/sync +1 -1
- data/scout_commands/system/clean +7 -7
- data/scout_commands/system/status +4 -4
- data/scout_commands/template +1 -1
- data/scout_commands/update +1 -1
- data/scout_commands/workflow/cmd +2 -1
- data/scout_commands/workflow/example +123 -0
- data/scout_commands/workflow/info +10 -1
- data/scout_commands/workflow/install +1 -1
- data/scout_commands/workflow/list +2 -2
- data/scout_commands/workflow/process +2 -2
- data/scout_commands/workflow/prov +3 -3
- data/scout_commands/workflow/task +36 -11
- data/scout_commands/workflow/trace +1 -1
- data/scout_commands/workflow/write_info +2 -2
- data/share/templates/command +1 -1
- data/test/scout/association/test_item.rb +5 -0
- data/test/scout/entity/test_property.rb +3 -3
- data/test/scout/knowledge_base/test_description.rb +1 -1
- data/test/scout/knowledge_base/test_traverse.rb +2 -2
- data/test/scout/persist/engine/test_packed_index.rb +6 -6
- data/test/scout/persist/test_tsv.rb +4 -4
- data/test/scout/persist/tsv/adapter/test_packed_index.rb +4 -4
- data/test/scout/persist/tsv/adapter/test_sharder.rb +23 -23
- data/test/scout/persist/tsv/adapter/test_tokyocabinet.rb +1 -1
- data/test/scout/persist/tsv/test_serialize.rb +1 -1
- data/test/scout/test_association.rb +1 -1
- data/test/scout/test_tsv.rb +2 -2
- data/test/scout/test_workflow.rb +2 -2
- data/test/scout/tsv/test_annotation.rb +4 -4
- data/test/scout/tsv/test_index.rb +1 -1
- data/test/scout/tsv/test_open.rb +2 -2
- data/test/scout/tsv/test_parser.rb +2 -2
- data/test/scout/tsv/test_stream.rb +1 -1
- data/test/scout/tsv/test_transformer.rb +1 -1
- data/test/scout/tsv/util/test_filter.rb +1 -1
- data/test/scout/tsv/util/test_melt.rb +1 -1
- data/test/scout/tsv/util/test_reorder.rb +1 -1
- data/test/scout/work_queue/test_socket.rb +3 -3
- data/test/scout/work_queue/test_worker.rb +2 -2
- data/test/scout/workflow/deployment/orchestrator/test_batches.rb +13 -3
- data/test/scout/workflow/deployment/orchestrator/test_chains.rb +15 -13
- data/test/scout/workflow/deployment/orchestrator/test_workload.rb +1 -1
- data/test/scout/workflow/deployment/test_local.rb +2 -2
- data/test/scout/workflow/deployment/test_scheduler.rb +1 -2
- data/test/scout/workflow/step/test_children.rb +1 -1
- data/test/scout/workflow/step/test_dependencies.rb +36 -1
- data/test/scout/workflow/step/test_info.rb +3 -35
- data/test/scout/workflow/step/test_load.rb +1 -1
- data/test/scout/workflow/step/test_provenance.rb +1 -1
- data/test/scout/workflow/step/test_status.rb +33 -1
- data/test/scout/workflow/task/test_dependencies.rb +9 -7
- data/test/scout/workflow/task/test_inputs.rb +1 -1
- data/test/scout/workflow/test_definition.rb +1 -1
- data/test/scout/workflow/test_documentation.rb +1 -1
- data/test/scout/workflow/test_entity.rb +2 -2
- data/test/scout/workflow/test_step.rb +13 -13
- data/test/scout/workflow/test_usage.rb +1 -1
- data/test/test_helper.rb +1 -1
- metadata +3 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require_relative 'job'
|
|
2
2
|
require 'scout'
|
|
3
3
|
|
|
4
|
-
module PBS
|
|
4
|
+
module PBS
|
|
5
5
|
extend SchedulerJob
|
|
6
6
|
|
|
7
7
|
def self.system
|
|
@@ -13,7 +13,7 @@ module PBS
|
|
|
13
13
|
let TOTAL_PROCESORS="$(cat /proc/cpuinfo|grep ^processor |wc -l)"
|
|
14
14
|
let MAX_MEMORY_DEFAULT="$(grep MemTotal /proc/meminfo|grep -o "[[:digit:]]*") / ( (1024 * $TOTAL_PROCESORS) / $PBS_CPUS_PER_TASK )"
|
|
15
15
|
MAX_MEMORY="$MAX_MEMORY_DEFAULT"
|
|
16
|
-
[ ! -z $PBS_MEM_PER_CPU ] && let MAX_MEMORY="$PBS_MEM_PER_CPU * $PBS_CPUS_PER_TASK"
|
|
16
|
+
[ ! -z $PBS_MEM_PER_CPU ] && let MAX_MEMORY="$PBS_MEM_PER_CPU * $PBS_CPUS_PER_TASK"
|
|
17
17
|
[ ! -z $PBS_MEM_PER_NODE ] && MAX_MEMORY="$PBS_MEM_PER_NODE"
|
|
18
18
|
export MAX_MEMORY_DEFAULT
|
|
19
19
|
export MAX_MEMORY
|
|
@@ -36,7 +36,7 @@ cd ${PBS_O_WORKDIR}
|
|
|
36
36
|
time = IndiferentHash.process_options options, :time
|
|
37
37
|
nodes = IndiferentHash.process_options options, :nodes
|
|
38
38
|
|
|
39
|
-
# PBS
|
|
39
|
+
# PBS
|
|
40
40
|
place = IndiferentHash.process_options options, :place, :place => 'scatter'
|
|
41
41
|
system = IndiferentHash.process_options options, :partition
|
|
42
42
|
filesystems = IndiferentHash.process_options options, :filesystems
|
|
@@ -45,7 +45,7 @@ cd ${PBS_O_WORKDIR}
|
|
|
45
45
|
|
|
46
46
|
filesystems = filesystems * "," if Array === filesystems
|
|
47
47
|
|
|
48
|
-
# NOT USED
|
|
48
|
+
# NOT USED
|
|
49
49
|
partition = IndiferentHash.process_options options, :partition
|
|
50
50
|
task_cpus = IndiferentHash.process_options options, :task_cpus
|
|
51
51
|
exclusive = IndiferentHash.process_options options, :exclusive
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require_relative 'job'
|
|
2
2
|
require 'scout'
|
|
3
3
|
|
|
4
|
-
module SLURM
|
|
4
|
+
module SLURM
|
|
5
5
|
|
|
6
6
|
extend SchedulerJob
|
|
7
7
|
|
|
@@ -15,7 +15,7 @@ module SLURM
|
|
|
15
15
|
let TOTAL_PROCESORS="$(cat /proc/cpuinfo|grep ^processor |wc -l)"
|
|
16
16
|
let MAX_MEMORY_DEFAULT="$(grep MemTotal /proc/meminfo|grep -o "[[:digit:]]*") / ( (1024 * $TOTAL_PROCESORS) / $SLURM_CPUS_PER_TASK )"
|
|
17
17
|
MAX_MEMORY="$MAX_MEMORY_DEFAULT"
|
|
18
|
-
[ ! -z $SLURM_MEM_PER_CPU ] && let MAX_MEMORY="$SLURM_MEM_PER_CPU * $SLURM_CPUS_PER_TASK"
|
|
18
|
+
[ ! -z $SLURM_MEM_PER_CPU ] && let MAX_MEMORY="$SLURM_MEM_PER_CPU * $SLURM_CPUS_PER_TASK"
|
|
19
19
|
[ ! -z $SLURM_MEM_PER_NODE ] && MAX_MEMORY="$SLURM_MEM_PER_NODE"
|
|
20
20
|
export MAX_MEMORY_DEFAULT
|
|
21
21
|
export MAX_MEMORY
|
|
@@ -12,31 +12,42 @@ module Workflow::Scheduler
|
|
|
12
12
|
Workflow::Scheduler.process_batches(batches, options)
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
+
def self.produce_single_batch(job, rules = {}, options = {})
|
|
16
|
+
batches = Workflow::Orchestrator.job_batches(rules, job)
|
|
17
|
+
rules = batches.inject({}){|acc,b| acc = Workflow::Orchestrator.accumulate_rules acc, b[:rules] }
|
|
18
|
+
|
|
19
|
+
max_time = batches.collect{|b| b[:rules][:time] }.max
|
|
20
|
+
rules[:time] = options.include?(:time) ? options[:time] : max_time
|
|
21
|
+
rules[:deploy] = :local
|
|
22
|
+
if rules[:exclusive]
|
|
23
|
+
rules[:task_cpus] = nil
|
|
24
|
+
rules[:cpus] = nil
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
batch = {top_level: job, jobs: [job], rules: rules, deps: [] }
|
|
28
|
+
Workflow::Scheduler.process_batches([batch], options)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
|
|
15
32
|
def self.process_batches(batches, process_options = {})
|
|
16
33
|
failed_jobs = []
|
|
17
34
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
sorted = []
|
|
21
|
-
while pending.any?
|
|
22
|
-
leaf_nodes = batches.select{|batch| (batch[:deps] - sorted).empty? }
|
|
23
|
-
sorted.concat(leaf_nodes - sorted)
|
|
24
|
-
pending -= leaf_nodes
|
|
25
|
-
end
|
|
35
|
+
sorted = Workflow::Orchestrator.sort_batches batches
|
|
36
|
+
cleaned = Workflow::Orchestrator.clean_batches sorted
|
|
26
37
|
|
|
27
38
|
batch_system = Scout::Config.get :system, :batch, :scheduler, 'env:BATCH_SYSTEM', default: 'SLURM'
|
|
28
39
|
|
|
29
40
|
batch_ids = {}
|
|
30
|
-
|
|
41
|
+
cleaned.collect do |batch|
|
|
31
42
|
job_options = batch[:rules]
|
|
32
43
|
job_options = IndiferentHash.add_defaults job_options, process_options.dup
|
|
33
44
|
|
|
34
45
|
if batch[:deps].nil?
|
|
35
|
-
batch_dependencies = []
|
|
36
|
-
else
|
|
46
|
+
batch_dependencies = []
|
|
47
|
+
else
|
|
37
48
|
top_jobs = batch[:jobs]
|
|
38
49
|
|
|
39
|
-
batch_dependencies = batch[:deps].collect{|dep|
|
|
50
|
+
batch_dependencies = batch[:deps].collect{|dep|
|
|
40
51
|
dep_target = dep[:top_level]
|
|
41
52
|
id = batch_ids[dep_target].to_s
|
|
42
53
|
|
|
@@ -132,10 +132,10 @@ module Workflow
|
|
|
132
132
|
info[:time] << time
|
|
133
133
|
|
|
134
134
|
report_keys.each do |key|
|
|
135
|
-
info[key] = dep_info[key]
|
|
135
|
+
info[key] = dep_info[key]
|
|
136
136
|
end
|
|
137
137
|
|
|
138
|
-
dep.info[:config_keys].each do |kinfo|
|
|
138
|
+
dep.info[:config_keys].each do |kinfo|
|
|
139
139
|
key, value, tokens = kinfo
|
|
140
140
|
|
|
141
141
|
info[key.to_s] = value if report_keys.include? key.to_s
|
|
@@ -31,7 +31,7 @@ module Workflow
|
|
|
31
31
|
title = doc_parse_first_line doc
|
|
32
32
|
description, task_info = doc_parse_up_to doc, /^# Tasks/i
|
|
33
33
|
task_description, tasks = doc_parse_up_to task_info, /^##/, true
|
|
34
|
-
tasks = doc_parse_chunks tasks, /^## (.*)/
|
|
34
|
+
tasks = doc_parse_chunks tasks, /^## (.*)/
|
|
35
35
|
{:title => title.strip, :description => description.strip, :task_description => task_description.strip, :tasks => tasks}
|
|
36
36
|
end
|
|
37
37
|
|
|
@@ -52,11 +52,11 @@ module Workflow
|
|
|
52
52
|
documentation = Workflow.parse_workflow_doc documentation_markdown
|
|
53
53
|
|
|
54
54
|
if @description && (documentation[:description].nil? || documentation[:description].empty?)
|
|
55
|
-
documentation[:description] = @description
|
|
55
|
+
documentation[:description] = @description
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
if @title && (documentation[:title].nil? || documentation[:title].empty?)
|
|
59
|
-
documentation[:title] = @title
|
|
59
|
+
documentation[:title] = @title
|
|
60
60
|
end
|
|
61
61
|
documentation[:tasks].each do |task, description|
|
|
62
62
|
if task.include? "#"
|
|
@@ -74,7 +74,7 @@ module Workflow
|
|
|
74
74
|
if workflow.tasks.include? task
|
|
75
75
|
workflow.tasks[task].description = description
|
|
76
76
|
else
|
|
77
|
-
Log.low "Documentation for #{ task }, but not a #{ workflow.to_s } task"
|
|
77
|
+
Log.low "Documentation for #{ task }, but not a #{ workflow.to_s } task"
|
|
78
78
|
end
|
|
79
79
|
end
|
|
80
80
|
documentation
|
data/lib/scout/workflow/path.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
class Step
|
|
2
|
+
|
|
2
3
|
def rec_dependencies(connected = false, seen = Set.new)
|
|
3
4
|
@rec_dependencies = {}
|
|
4
5
|
@rec_dependencies[connected] ||= begin
|
|
@@ -34,6 +35,31 @@ class Step
|
|
|
34
35
|
end.compact.uniq
|
|
35
36
|
end
|
|
36
37
|
|
|
38
|
+
def overrider?
|
|
39
|
+
! (overriden_task.nil? && overriden_workflow.nil?)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def overriden?
|
|
43
|
+
@overriden
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def overriden_deps
|
|
47
|
+
dependencies.select{|d| d.overriden? }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def recursive_overriden_deps
|
|
51
|
+
overriden_deps = self.overriden_deps
|
|
52
|
+
overriden_deps + overriden_deps.collect{|dep| dep.recursive_overriden_deps }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def overrider_deps
|
|
56
|
+
dependencies.select{|d| d.overrider? }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def recursive_overrider_deps
|
|
60
|
+
self.rec_dependencies.select{|dep| dep.overrider? }
|
|
61
|
+
end
|
|
62
|
+
|
|
37
63
|
def prepare_dependencies
|
|
38
64
|
inverse_dep = {}
|
|
39
65
|
|
|
@@ -44,7 +70,14 @@ class Step
|
|
|
44
70
|
end
|
|
45
71
|
|
|
46
72
|
next if dep.done?
|
|
47
|
-
|
|
73
|
+
|
|
74
|
+
if dep.error? && ! dep.recoverable_error?
|
|
75
|
+
if dep.canfail?
|
|
76
|
+
next
|
|
77
|
+
else
|
|
78
|
+
raise dep.exception
|
|
79
|
+
end
|
|
80
|
+
end
|
|
48
81
|
|
|
49
82
|
if dep.dependencies
|
|
50
83
|
dep.dependencies.each do |d|
|
|
@@ -74,7 +107,7 @@ class Step
|
|
|
74
107
|
end
|
|
75
108
|
|
|
76
109
|
def run_dependencies
|
|
77
|
-
all_dependencies.each do |dep|
|
|
110
|
+
all_dependencies.each do |dep|
|
|
78
111
|
next if dep.running? || dep.done?
|
|
79
112
|
next if dep.error? && ! dep.recoverable_error?
|
|
80
113
|
|
|
@@ -100,7 +133,7 @@ class Step
|
|
|
100
133
|
end
|
|
101
134
|
|
|
102
135
|
def abort_dependencies
|
|
103
|
-
all_dependencies.each{|dep| dep.abort if dep.running? }
|
|
136
|
+
all_dependencies.each{|dep| dep.abort if dep.running? }
|
|
104
137
|
end
|
|
105
138
|
|
|
106
139
|
def self.wait_for_jobs(jobs, canfail=false)
|
|
@@ -30,7 +30,8 @@ class Step
|
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
def save_info(info = nil)
|
|
33
|
-
|
|
33
|
+
purged = Annotation.purge(@info = info)
|
|
34
|
+
Persist.save(purged, info_file, SERIALIZER)
|
|
34
35
|
@info_load_time = Time.now
|
|
35
36
|
end
|
|
36
37
|
|
|
@@ -82,6 +83,7 @@ class Step
|
|
|
82
83
|
|
|
83
84
|
if start && eend
|
|
84
85
|
time = eend - start
|
|
86
|
+
Log.warn "No issue time #{self.path}" if issued.nil?
|
|
85
87
|
total_time = eend - issued
|
|
86
88
|
if total_time - time > 1
|
|
87
89
|
time_str = "#{Misc.format_seconds_short(time)} (#{Misc.format_seconds_short(total_time)})"
|
|
@@ -93,7 +95,7 @@ class Step
|
|
|
93
95
|
message = Log.color(:time, time_str)
|
|
94
96
|
end
|
|
95
97
|
end
|
|
96
|
-
report_status value, message
|
|
98
|
+
report_status value, message
|
|
97
99
|
end
|
|
98
100
|
|
|
99
101
|
if key == :message
|
|
@@ -136,7 +138,7 @@ class Step
|
|
|
136
138
|
def set_info(key, value)
|
|
137
139
|
merge_info(key => value)
|
|
138
140
|
end
|
|
139
|
-
|
|
141
|
+
|
|
140
142
|
def report_status(status, message = nil)
|
|
141
143
|
if message.nil?
|
|
142
144
|
Log.info [Log.color(:status, status, true), Log.color(:task, task_name, true), Log.color(:path, path)] * " "
|
|
@@ -184,22 +186,6 @@ class Step
|
|
|
184
186
|
! (done? && status == :done) && (info[:pid] && Misc.pid_alive?(info[:pid]))
|
|
185
187
|
end
|
|
186
188
|
|
|
187
|
-
def overriden?
|
|
188
|
-
@overriden = overriden_task || overriden_workflow || overriden_deps.any? if @overriden.nil?
|
|
189
|
-
@overriden
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
def overriden_deps
|
|
193
|
-
dependencies.select{|d| d.overriden? }
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
def recursive_overriden_deps
|
|
197
|
-
overriden_deps = dependencies.select{|d|
|
|
198
|
-
d.overriden?
|
|
199
|
-
}
|
|
200
|
-
(overriden_deps + overriden_deps.collect{|d| d.recursive_overriden_deps }).flatten.uniq
|
|
201
|
-
end
|
|
202
|
-
|
|
203
189
|
def exception
|
|
204
190
|
return nil unless info[:exception]
|
|
205
191
|
begin
|
|
@@ -3,7 +3,7 @@ class Step
|
|
|
3
3
|
if clean_name != name
|
|
4
4
|
#hash = name[clean_name.length..-1]
|
|
5
5
|
#inputs_dir += hash
|
|
6
|
-
Log.medium "Saving job inputs to: #{Log.fingerprint inputs_dir}"
|
|
6
|
+
Log.medium "Saving job inputs to: #{Log.fingerprint inputs_dir} #{Log.fingerprint provided_inputs}"
|
|
7
7
|
self.task.save_inputs(inputs_dir, provided_inputs)
|
|
8
8
|
else
|
|
9
9
|
Log.medium "Saving no input job: #{Log.fingerprint inputs_dir}"
|
|
@@ -58,10 +58,10 @@ class Step
|
|
|
58
58
|
str = if ! (Open.remote?(path) || Open.ssh?(path)) && (Open.exists?(path) && $main_mtime && path_mtime && ($main_mtime - path_mtime) < -2)
|
|
59
59
|
prov_status_msg(status.to_s) << " " << [workflow, task, path, input_str].compact * " " << " (#{Log.color(:red, "Mtime out of sync") })"
|
|
60
60
|
else
|
|
61
|
-
prov_status_msg(status.to_s) << " " << [workflow, task, path, input_str].compact * " "
|
|
61
|
+
prov_status_msg(status.to_s) << " " << [workflow, task, path, input_str].compact * " "
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
-
if $inputs and $inputs.any?
|
|
64
|
+
if $inputs and $inputs.any?
|
|
65
65
|
job_inputs = Step.new(path).recursive_inputs.to_hash
|
|
66
66
|
IndiferentHash.setup(job_inputs)
|
|
67
67
|
|
|
@@ -119,7 +119,7 @@ class Step
|
|
|
119
119
|
step.dependencies.each do |dep|
|
|
120
120
|
if dep.input_dependencies.any?
|
|
121
121
|
dep.input_dependencies.each do |id|
|
|
122
|
-
input_name, _dep = dep.recursive_inputs.select{|f,d|
|
|
122
|
+
input_name, _dep = dep.recursive_inputs.select{|f,d|
|
|
123
123
|
d == id || (String === d && d.start_with?(id.files_dir)) || (Array === d && d.include?(id))
|
|
124
124
|
}.keys.last
|
|
125
125
|
if input_name
|
|
@@ -135,7 +135,7 @@ class Step
|
|
|
135
135
|
indent = prov_indent(step, offset, input_dependencies)
|
|
136
136
|
str << indent + this_step_msg if ENV["SCOUT_ORIGINAL_STACK"] == 'true'
|
|
137
137
|
|
|
138
|
-
step.dependencies.dup.tap{|l|
|
|
138
|
+
step.dependencies.dup.tap{|l|
|
|
139
139
|
l.reverse! if ENV["SCOUT_ORIGINAL_STACK"] == 'true'
|
|
140
140
|
}.each do |dep|
|
|
141
141
|
path = dep.path
|
|
@@ -5,7 +5,7 @@ class Step
|
|
|
5
5
|
begin
|
|
6
6
|
s = Misc.abort_child pid, true
|
|
7
7
|
Log.medium "Aborted pid #{path} #{s}"
|
|
8
|
-
rescue
|
|
8
|
+
rescue
|
|
9
9
|
Log.debug("Aborted job #{pid} was not killed: #{$!.message}")
|
|
10
10
|
end
|
|
11
11
|
else
|
|
@@ -17,35 +17,49 @@ class Step
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def recoverable_error?
|
|
20
|
-
self.error? && ! (ScoutException === self.exception)
|
|
20
|
+
self.error? && ! (ENV['SCOUT_NO_RECOVERABLE_ERROR'].to_s.downcase == 'true') && ! (ScoutException === self.exception)
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def newer_dependencies
|
|
24
|
+
rec_dependencies = self.rec_dependencies
|
|
25
|
+
rec_dependencies = rec_dependencies.select{|dep| Open.exists?(dep.info_file) }
|
|
26
|
+
rec_dependencies = rec_dependencies.reject{|dep| dep.error? && ! dep.recoverable_error? }
|
|
24
27
|
newer = rec_dependencies.select{|dep| Path.newer?(self.path, dep.path) }
|
|
25
28
|
newer += input_dependencies.select{|dep| Path.newer?(self.path, dep.path) }
|
|
26
29
|
newer += rec_dependencies.collect{|dep| dep.input_dependencies }.flatten.select{|dep| Path.newer?(self.path, dep.path) }
|
|
27
30
|
newer
|
|
28
31
|
end
|
|
29
32
|
|
|
33
|
+
def cleaned_dependencies
|
|
34
|
+
return []
|
|
35
|
+
rec_dependencies = self.rec_dependencies
|
|
36
|
+
cleaned = rec_dependencies.select{|dep| dep.info[:status] == :cleaned }
|
|
37
|
+
cleaned += input_dependencies.select{|dep| dep.info[:status] == :cleaned }
|
|
38
|
+
cleaned += rec_dependencies.collect{|dep| dep.input_dependencies }.flatten.select{|dep| dep.info[:status] == :cleaned }
|
|
39
|
+
cleaned
|
|
40
|
+
end
|
|
41
|
+
|
|
30
42
|
def updated?
|
|
31
43
|
return false if self.error? && self.recoverable_error?
|
|
32
|
-
return true if (self.done? || (self.error? && ! self.recoverable_error?)) && ! ENV["SCOUT_UPDATE"]
|
|
44
|
+
return true if (self.done? || (self.error? && ! self.recoverable_error?)) && ! ENV["SCOUT_UPDATE"].to_s.downcase == 'true'
|
|
33
45
|
newer = newer_dependencies
|
|
46
|
+
cleaned = cleaned_dependencies
|
|
34
47
|
|
|
35
48
|
Log.low "Newer deps found for #{Log.fingerprint self}: #{Log.fingerprint newer}" if newer.any?
|
|
36
|
-
|
|
49
|
+
Log.low "Cleaned deps found for #{Log.fingerprint self}: #{Log.fingerprint cleaned}" if cleaned.any?
|
|
50
|
+
newer.empty? && cleaned.empty?
|
|
37
51
|
end
|
|
38
52
|
|
|
39
53
|
def clean
|
|
40
54
|
Log.debug "Cleaning job files: #{path}"
|
|
41
|
-
@take_stream = nil
|
|
55
|
+
@take_stream = nil
|
|
42
56
|
@result = nil
|
|
43
57
|
@info = nil
|
|
44
58
|
@info_load_time = nil
|
|
45
59
|
@done = nil
|
|
46
|
-
Open.rm path if Open.exist_or_link?(path)
|
|
47
|
-
Open.rm tmp_path if Open.exist_or_link?(tmp_path)
|
|
48
|
-
Open.rm info_file if Open.exist_or_link?(info_file)
|
|
60
|
+
Open.rm path if Open.exist_or_link?(path) && Path.can_write?(path)
|
|
61
|
+
Open.rm tmp_path if Open.exist_or_link?(tmp_path) && Path.can_write?(tmp_path)
|
|
62
|
+
Open.rm info_file if Open.exist_or_link?(info_file) && Path.can_write?(info_file)
|
|
49
63
|
Open.rm_rf files_dir if Open.exist_or_link?(files_dir)
|
|
50
64
|
self
|
|
51
65
|
end
|
|
@@ -59,7 +73,7 @@ class Step
|
|
|
59
73
|
dependencies.each do |dep|
|
|
60
74
|
dep.recursive_clean
|
|
61
75
|
end
|
|
62
|
-
clean
|
|
76
|
+
clean if Open.exists?(self.info_file)
|
|
63
77
|
end
|
|
64
78
|
|
|
65
79
|
def canfail?
|
data/lib/scout/workflow/step.rb
CHANGED
|
@@ -13,17 +13,18 @@ require_relative 'step/inputs'
|
|
|
13
13
|
require_relative 'step/children'
|
|
14
14
|
require_relative 'step/archive'
|
|
15
15
|
|
|
16
|
-
class Step
|
|
16
|
+
class Step
|
|
17
17
|
|
|
18
18
|
attr_accessor :path, :inputs, :dependencies, :id, :task, :tee_copies, :non_default_inputs, :provided_inputs, :compute, :overriden_task, :overriden_workflow, :workflow, :exec_context, :overriden
|
|
19
|
-
def initialize(path = nil, inputs = nil, dependencies = nil, id = nil, non_default_inputs = nil, provided_inputs = nil, compute = nil, exec_context: nil, &task)
|
|
19
|
+
def initialize(path = nil, inputs = nil, dependencies = nil, id = nil, non_default_inputs = nil, provided_inputs = nil, compute = nil, overriden = nil, exec_context: nil, &task)
|
|
20
20
|
@path = path
|
|
21
21
|
@inputs = inputs
|
|
22
22
|
@dependencies = dependencies
|
|
23
23
|
@id = id
|
|
24
24
|
@non_default_inputs = non_default_inputs
|
|
25
25
|
@provided_inputs = provided_inputs
|
|
26
|
-
@compute = compute
|
|
26
|
+
@compute = compute
|
|
27
|
+
@overriden = overriden unless overriden.nil?
|
|
27
28
|
@task = task
|
|
28
29
|
@mutex = Mutex.new
|
|
29
30
|
@tee_copies = 1
|
|
@@ -36,12 +37,12 @@ class Step
|
|
|
36
37
|
|
|
37
38
|
def provided_inputs
|
|
38
39
|
@provided_inputs ||= begin
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
if info_file && Open.exists?(info_file)
|
|
41
|
+
info[:provided_inputs]
|
|
42
|
+
else
|
|
43
|
+
{}
|
|
44
|
+
end
|
|
45
|
+
end
|
|
45
46
|
end
|
|
46
47
|
|
|
47
48
|
def non_default_inputs
|
|
@@ -97,7 +98,7 @@ class Step
|
|
|
97
98
|
return @id if @id
|
|
98
99
|
return info[:clean_name] if info.include? :clean_name
|
|
99
100
|
if m = name.match(/(.+?)(?:_[a-z0-9]{32})?(?:\..*)?$/)
|
|
100
|
-
return m[1]
|
|
101
|
+
return m[1]
|
|
101
102
|
end
|
|
102
103
|
return name.split(".").first
|
|
103
104
|
end
|
|
@@ -189,9 +190,10 @@ class Step
|
|
|
189
190
|
end
|
|
190
191
|
end
|
|
191
192
|
|
|
192
|
-
|
|
193
193
|
return @result || self.load if done?
|
|
194
|
+
|
|
194
195
|
prepare_dependencies
|
|
196
|
+
|
|
195
197
|
begin
|
|
196
198
|
|
|
197
199
|
|
|
@@ -200,11 +202,11 @@ class Step
|
|
|
200
202
|
|
|
201
203
|
|
|
202
204
|
reset_info :status => :setup, :issued => Time.now,
|
|
203
|
-
:pid => Process.pid, :pid_hostname => Misc.hostname,
|
|
205
|
+
:pid => Process.pid, :pid_hostname => Misc.hostname,
|
|
204
206
|
:task_name => task_name, :workflow => workflow.to_s,
|
|
205
|
-
:provided_inputs =>
|
|
207
|
+
:provided_inputs => IndiferentHash.serializable(provided_inputs),
|
|
206
208
|
:non_default_inputs => non_default_inputs,
|
|
207
|
-
:inputs =>
|
|
209
|
+
:inputs => IndiferentHash.serializable(inputs), :input_names => input_names, :type => type,
|
|
208
210
|
:dependencies => (dependencies || []) .collect{|d| d.path }
|
|
209
211
|
|
|
210
212
|
run_dependencies
|
|
@@ -313,7 +315,7 @@ class Step
|
|
|
313
315
|
end
|
|
314
316
|
|
|
315
317
|
def streaming?
|
|
316
|
-
@take_stream || IO === @result || StringIO === @result
|
|
318
|
+
@take_stream || IO === @result || StringIO === @result
|
|
317
319
|
end
|
|
318
320
|
|
|
319
321
|
def stream
|
|
@@ -344,16 +346,16 @@ class Step
|
|
|
344
346
|
end
|
|
345
347
|
|
|
346
348
|
def consume_all_streams
|
|
347
|
-
threads = []
|
|
349
|
+
threads = []
|
|
348
350
|
while @result && streaming? && stream = self.stream
|
|
349
351
|
threads << Open.consume_stream(stream, true)
|
|
350
352
|
end
|
|
351
353
|
|
|
352
354
|
threads.compact!
|
|
353
355
|
|
|
354
|
-
threads.each do |t|
|
|
356
|
+
threads.each do |t|
|
|
355
357
|
begin
|
|
356
|
-
t.join
|
|
358
|
+
t.join
|
|
357
359
|
rescue Exception
|
|
358
360
|
threads.compact.each{|t| t.raise(Aborted); t.join }
|
|
359
361
|
raise $!
|
|
@@ -388,7 +390,7 @@ class Step
|
|
|
388
390
|
|
|
389
391
|
raise self.exception if self.exception
|
|
390
392
|
|
|
391
|
-
raise "Error in job #{self.path}" if self.error? or self.aborted?
|
|
393
|
+
raise "Error in job #{self.path}" if self.error? or self.aborted?
|
|
392
394
|
|
|
393
395
|
self
|
|
394
396
|
end
|
|
@@ -2,7 +2,7 @@ module Task
|
|
|
2
2
|
def dependencies(id, provided_inputs, non_default_inputs = [], compute = {})
|
|
3
3
|
return [] if deps.nil?
|
|
4
4
|
dependencies = []
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
provided_inputs ||= {}
|
|
7
7
|
|
|
8
8
|
# Helper function
|
|
@@ -66,8 +66,15 @@ module Task
|
|
|
66
66
|
|
|
67
67
|
if provided_inputs.include?(overriden = [workflow.name, task] * "#")
|
|
68
68
|
dep = provided_inputs[overriden]
|
|
69
|
-
dep =
|
|
70
|
-
|
|
69
|
+
dep = case dep
|
|
70
|
+
when Step
|
|
71
|
+
dep
|
|
72
|
+
when String
|
|
73
|
+
Step.new dep
|
|
74
|
+
when Symbol
|
|
75
|
+
dependencies.select{|dep| dep.task_name == dep }.last
|
|
76
|
+
end
|
|
77
|
+
|
|
71
78
|
dep.type = workflow.tasks[task].type
|
|
72
79
|
dep.overriden_task = task
|
|
73
80
|
dep.overriden_workflow = workflow
|
|
@@ -42,8 +42,8 @@ module Workflow
|
|
|
42
42
|
def rec_input_use(task_name)
|
|
43
43
|
input_use = {}
|
|
44
44
|
task = self.tasks[task_name]
|
|
45
|
-
task.inputs.each do |name,_|
|
|
46
|
-
input_use[name] ||= {}
|
|
45
|
+
task.inputs.each do |name,_|
|
|
46
|
+
input_use[name] ||= {}
|
|
47
47
|
input_use[name][self] ||= []
|
|
48
48
|
input_use[name][self] << task_name
|
|
49
49
|
end
|
|
@@ -69,7 +69,7 @@ module Workflow
|
|
|
69
69
|
raise "No '#{name}' task in '#{self.name}' Workflow" if task.nil?
|
|
70
70
|
id = File.join(self.name, name.to_s)
|
|
71
71
|
@task_info ||= {}
|
|
72
|
-
@task_info[id] ||= begin
|
|
72
|
+
@task_info[id] ||= begin
|
|
73
73
|
description = task.description
|
|
74
74
|
returns = task.returns
|
|
75
75
|
|
|
@@ -3,9 +3,9 @@ module Task
|
|
|
3
3
|
def self.format_input(value, type, options = {})
|
|
4
4
|
return value if IO === value || StringIO === value || Step === value
|
|
5
5
|
|
|
6
|
-
if String === value && ! [:path, :file, :folder, :binary, :tsv].include?(type) && ! (options && (options[:noload] || options[:stream] || options[:nofile] || options[:asfile]))
|
|
6
|
+
if String === value && Path.is_filename?(value) && ! [:path, :file, :folder, :binary, :tsv].include?(type) && ! (options && (options[:noload] || options[:stream] || options[:nofile] || options[:asfile]))
|
|
7
7
|
if Open.exists?(value) && ! Open.directory?(value)
|
|
8
|
-
Persist.load(value, type)
|
|
8
|
+
Persist.load(value, type)
|
|
9
9
|
else
|
|
10
10
|
Persist.deserialize(value, type)
|
|
11
11
|
end
|
|
@@ -96,7 +96,7 @@ module Task
|
|
|
96
96
|
basename += "-#{digest}"
|
|
97
97
|
end
|
|
98
98
|
new_file = File.join(directory, 'saved_input_files', basename)
|
|
99
|
-
relative_file = File.join('.', 'saved_input_files', basename)
|
|
99
|
+
relative_file = File.join('.', 'saved_input_files', basename)
|
|
100
100
|
Open.link orig_file, new_file
|
|
101
101
|
relative_file
|
|
102
102
|
end
|
|
@@ -104,7 +104,7 @@ module Task
|
|
|
104
104
|
def self.save_input(directory, name, type, value)
|
|
105
105
|
input_file = File.join(directory, name.to_s)
|
|
106
106
|
|
|
107
|
-
if Path.is_filename?(value)
|
|
107
|
+
if Path.is_filename?(value)
|
|
108
108
|
if type == :path
|
|
109
109
|
Open.write(input_file + ".as_path", value)
|
|
110
110
|
elsif Path.step_file?(value)
|
|
@@ -114,7 +114,7 @@ module Task
|
|
|
114
114
|
Open.write(input_file + ".as_file", relative_file)
|
|
115
115
|
end
|
|
116
116
|
elsif Step === value
|
|
117
|
-
Open.write(input_file + ".as_step", value.
|
|
117
|
+
Open.write(input_file + ".as_step", value.identify_path)
|
|
118
118
|
elsif type == :file
|
|
119
119
|
relative_file = save_file_input(value, directory)
|
|
120
120
|
Persist.save(relative_file, input_file, :file)
|
|
@@ -153,8 +153,8 @@ module Task
|
|
|
153
153
|
value.sub!(/^\./, File.dirname(filename)) if value.start_with?("./")
|
|
154
154
|
value
|
|
155
155
|
elsif filename.end_with?('.as_step')
|
|
156
|
-
value = Open.read(filename).strip
|
|
157
|
-
Step.load value
|
|
156
|
+
value = Path.setup Open.read(filename).strip
|
|
157
|
+
Step.load value.find
|
|
158
158
|
elsif filename.end_with?('.as_path')
|
|
159
159
|
value = Open.read(filename).strip
|
|
160
160
|
Path.setup value
|
|
@@ -183,7 +183,7 @@ module Task
|
|
|
183
183
|
self.recursive_inputs.each do |p|
|
|
184
184
|
name, type, desc, value, options = p
|
|
185
185
|
next if seen.include?(name)
|
|
186
|
-
filename = File.join(directory, name.to_s)
|
|
186
|
+
filename = File.join(directory, name.to_s)
|
|
187
187
|
value = Task.load_input_from_file(filename, type, options)
|
|
188
188
|
inputs[name] = value unless value.nil?
|
|
189
189
|
seen << name
|