tengine_job 0.6.9
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +23 -0
- data/Gemfile.lock +109 -0
- data/README.rdoc +20 -0
- data/Rakefile +42 -0
- data/VERSION +1 -0
- data/examples/0004_retry_one_layer.rb +24 -0
- data/examples/0004_retry_one_layer.sh +38 -0
- data/examples/0005_retry_two_layer.rb +54 -0
- data/examples/0005_retry_two_layer.sh +80 -0
- data/examples/0006_retry_three_layer.rb +58 -0
- data/examples/0006_retry_three_layer.sh +74 -0
- data/examples/0007_simple_jobnet.rb +7 -0
- data/examples/0021_dynamic_env.rb +20 -0
- data/examples/VERSION +1 -0
- data/examples/tengine_job_test.sh +10 -0
- data/lib/tengine/job.rb +94 -0
- data/lib/tengine/job/category.rb +54 -0
- data/lib/tengine/job/connectable.rb +43 -0
- data/lib/tengine/job/drivers/job_control_driver.rb +82 -0
- data/lib/tengine/job/drivers/job_execution_driver.rb +30 -0
- data/lib/tengine/job/drivers/jobnet_control_driver.rb +117 -0
- data/lib/tengine/job/drivers/schedule_driver.rb +30 -0
- data/lib/tengine/job/dsl_binder.rb +12 -0
- data/lib/tengine/job/dsl_evaluator.rb +18 -0
- data/lib/tengine/job/dsl_loader.rb +180 -0
- data/lib/tengine/job/edge.rb +150 -0
- data/lib/tengine/job/element_selector_notation.rb +169 -0
- data/lib/tengine/job/end.rb +32 -0
- data/lib/tengine/job/executable.rb +74 -0
- data/lib/tengine/job/execution.rb +141 -0
- data/lib/tengine/job/expansion.rb +37 -0
- data/lib/tengine/job/fork.rb +6 -0
- data/lib/tengine/job/job.rb +23 -0
- data/lib/tengine/job/jobnet.rb +173 -0
- data/lib/tengine/job/jobnet/builder.rb +150 -0
- data/lib/tengine/job/jobnet/job_state_transition.rb +167 -0
- data/lib/tengine/job/jobnet/jobnet_state_transition.rb +110 -0
- data/lib/tengine/job/jobnet/state_transition.rb +37 -0
- data/lib/tengine/job/jobnet_actual.rb +55 -0
- data/lib/tengine/job/jobnet_template.rb +10 -0
- data/lib/tengine/job/join.rb +6 -0
- data/lib/tengine/job/junction.rb +29 -0
- data/lib/tengine/job/killing.rb +30 -0
- data/lib/tengine/job/mm_compatibility.rb +6 -0
- data/lib/tengine/job/mm_compatibility/connectable.rb +13 -0
- data/lib/tengine/job/name_path.rb +31 -0
- data/lib/tengine/job/root.rb +16 -0
- data/lib/tengine/job/root_jobnet_actual.rb +39 -0
- data/lib/tengine/job/root_jobnet_template.rb +49 -0
- data/lib/tengine/job/script_executable.rb +235 -0
- data/lib/tengine/job/signal.rb +121 -0
- data/lib/tengine/job/start.rb +20 -0
- data/lib/tengine/job/stoppable.rb +15 -0
- data/lib/tengine/job/vertex.rb +172 -0
- data/lib/tengine_job.rb +3 -0
- data/spec/fixtures/rjn_0001_simple_jobnet_builder.rb +42 -0
- data/spec/fixtures/rjn_0002_simple_parallel_jobnet_builder.rb +42 -0
- data/spec/fixtures/rjn_0003_fork_join_jobnet_builder.rb +61 -0
- data/spec/fixtures/rjn_0004_parallel_jobnet_with_finally_fixture.rb +62 -0
- data/spec/fixtures/rjn_0005_retry_two_layer_fixture.rb +153 -0
- data/spec/fixtures/rjn_0008_expansion_fixture.rb +32 -0
- data/spec/fixtures/rjn_0009_tree_sequential_jobnet_builder.rb +174 -0
- data/spec/fixtures/rjn_0010_2jobs_and_1job_parallel_jobnet_builder.rb +39 -0
- data/spec/fixtures/rjn_0011_nested_fork_jobnet_builder.rb +96 -0
- data/spec/fixtures/rjn_0012_nested_and_finally_builder.rb +157 -0
- data/spec/fixtures/rjn_1004_hadoop_job_in_jobnet_fixture.rb +105 -0
- data/spec/fixtures/rjn_means_root_jobnet +0 -0
- data/spec/fixtures/test_credential_fixture.rb +12 -0
- data/spec/fixtures/test_server_fixture.rb +28 -0
- data/spec/mongoid.yml +35 -0
- data/spec/spec_helper.rb +56 -0
- data/spec/sshd/.gitignore +1 -0
- data/spec/sshd/id_rsa +51 -0
- data/spec/sshd/id_rsa.pub +1 -0
- data/spec/sshd/ssh_host_rsa_key +51 -0
- data/spec/sshd/ssh_host_rsa_key.pub +1 -0
- data/spec/sshd/sshd_config +10 -0
- data/spec/sshd/sshd_config.erb +11 -0
- data/spec/sshd/tengine_job_test.sh +6 -0
- data/spec/support/jobnet_fixture_builder.rb +145 -0
- data/spec/support/mongo_index_key_log.rb +91 -0
- data/spec/tengine/job/category_spec.rb +193 -0
- data/spec/tengine/job/connectable_spec.rb +94 -0
- data/spec/tengine/job/drivers/job_controll_driver/connection_error_spec.rb +236 -0
- data/spec/tengine/job/drivers/job_controll_driver/duplicated_job_start_spec.rb +302 -0
- data/spec/tengine/job/drivers/job_controll_driver/expansion_spec.rb +120 -0
- data/spec/tengine/job/drivers/job_controll_driver/stop_spec.rb +159 -0
- data/spec/tengine/job/drivers/job_controll_driver_spec.rb +623 -0
- data/spec/tengine/job/drivers/job_execution_driver_spec.rb +88 -0
- data/spec/tengine/job/drivers/jobnet_control_driver/nested_and_finally_spec.rb +472 -0
- data/spec/tengine/job/drivers/jobnet_control_driver/nested_jobnet_spec.rb +231 -0
- data/spec/tengine/job/drivers/jobnet_control_driver/stop_jobnet_spec.rb +202 -0
- data/spec/tengine/job/drivers/jobnet_control_driver_spec.rb +446 -0
- data/spec/tengine/job/drivers/schedule_driver_spec.rb +202 -0
- data/spec/tengine/job/dsl_binder_spec.rb +36 -0
- data/spec/tengine/job/dsl_loader_spec.rb +403 -0
- data/spec/tengine/job/dsls/0013_hadoop_job_run.rb +29 -0
- data/spec/tengine/job/dsls/0014_join_and_join.rb +19 -0
- data/spec/tengine/job/dsls/0015_fork_and_fork.rb +18 -0
- data/spec/tengine/job/dsls/0016_complex_fork_and_join.rb +20 -0
- data/spec/tengine/job/dsls/0017_finally.rb +15 -0
- data/spec/tengine/job/dsls/0018_expansion.rb +23 -0
- data/spec/tengine/job/dsls/0019_execute_job_on_event.rb +16 -0
- data/spec/tengine/job/dsls/0020_duplicated_jobnet_name.rb +16 -0
- data/spec/tengine/job/dsls/1060_test_dir1/1060_test_dir2/0013_hadoop_job_run.rb +29 -0
- data/spec/tengine/job/dsls/2003_expansion/expansion_5.rb +11 -0
- data/spec/tengine/job/dsls/VERSION +1 -0
- data/spec/tengine/job/dynamic_env_spec.rb +95 -0
- data/spec/tengine/job/edge_spec.rb +241 -0
- data/spec/tengine/job/element_selector_notation_spec.rb +354 -0
- data/spec/tengine/job/examples_spec.rb +62 -0
- data/spec/tengine/job/execution_spec.rb +100 -0
- data/spec/tengine/job/expansion_spec.rb +116 -0
- data/spec/tengine/job/hadoop_job_run_spec.rb +65 -0
- data/spec/tengine/job/job_spec.rb +4 -0
- data/spec/tengine/job/jobnet/1015_complecated_jobnet_spec.rb +72 -0
- data/spec/tengine/job/jobnet_actual_spec.rb +175 -0
- data/spec/tengine/job/jobnet_spec.rb +399 -0
- data/spec/tengine/job/jobnet_template_spec.rb +240 -0
- data/spec/tengine/job/killing_spec.rb +91 -0
- data/spec/tengine/job/reset_spec.rb +958 -0
- data/spec/tengine/job/reset_spec/4056_1_dump.txt +1 -0
- data/spec/tengine/job/root_jobnet_actual_spec.rb +89 -0
- data/spec/tengine/job/root_jobnet_template_spec.rb +248 -0
- data/spec/tengine/job/script_executable_spec.rb +132 -0
- data/spec/tengine/job/stoppable_spec.rb +176 -0
- data/spec/tengine/job/vertex_spec.rb +25 -0
- data/spec/tengine_job_spec.rb +4 -0
- data/tengine_job.gemspec +197 -0
- data/tmp/log/.gitignore +1 -0
- metadata +296 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'tengine/job'
|
3
|
+
|
4
|
+
# ジョブネットの終端を表すVertex。特に状態は持たない。
|
5
|
+
class Tengine::Job::End < Tengine::Job::Vertex
|
6
|
+
|
7
|
+
# https://cacoo.com/diagrams/hdLgrzYsTBBpV3Wj#D26C1
|
8
|
+
def transmit(signal)
|
9
|
+
activate(signal)
|
10
|
+
end
|
11
|
+
|
12
|
+
def activate(signal)
|
13
|
+
complete_origin_edge(signal, :except_closed => true)
|
14
|
+
parent = self.parent # Endのparentであるジョブネット
|
15
|
+
parent_finally = parent.finally_vertex
|
16
|
+
if parent_finally && (parent.phase_key != :dying)
|
17
|
+
parent_finally.transmit(signal)
|
18
|
+
else
|
19
|
+
parent.finish(signal)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def reset(signal)
|
24
|
+
parent = self.parent # Endのparentであるジョブネット
|
25
|
+
if signal.execution.in_scope?(parent)
|
26
|
+
if f = parent.finally_vertex
|
27
|
+
f.reset(signal)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'tengine/job'
|
3
|
+
require 'selectable_attr'
|
4
|
+
|
5
|
+
# ジョブ/ジョブネットを実行する際の情報に関するモジュール
|
6
|
+
# Tengine::Job::JobnetActual, Tengine::Job::JobnetTemplateがこのモジュールをincludeします
|
7
|
+
module Tengine::Job::Executable
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
class PhaseError < StandardError
|
11
|
+
end
|
12
|
+
|
13
|
+
included do
|
14
|
+
field :phase_cd , :type => Integer, :default => 20 # 進行状況。とりうる値は以下を参照してください。詳しくは「tengine_jobパッケージ設計書」の「ジョブ/ジョブネット状態遷移」を参照してください
|
15
|
+
field :started_at , :type => Time # 開始時刻。以前はDateTimeでしたが、実績ベースの予定終了時刻の計算のためにTimeにしました
|
16
|
+
field :finished_at, :type => Time # 終了時刻。強制終了時にも設定されます。
|
17
|
+
|
18
|
+
include Tengine::Core::SelectableAttr
|
19
|
+
selectable_attr :phase_cd do
|
20
|
+
entry 20, :initialized, 'initialized'
|
21
|
+
entry 30, :ready , "ready"
|
22
|
+
entry 50, :starting , "starting"
|
23
|
+
entry 60, :running , "running"
|
24
|
+
entry 70, :dying , "dying"
|
25
|
+
entry 40, :success , "success"
|
26
|
+
entry 80, :error , "error"
|
27
|
+
entry 90, :stuck , "stuck"
|
28
|
+
end
|
29
|
+
|
30
|
+
def phase_key=(phase_key)
|
31
|
+
element_type = nil
|
32
|
+
case self.class
|
33
|
+
when Tengine::Job::Execution then element_type = "execution"
|
34
|
+
when Tengine::Job::RootJobnetActual then element_type = "root_jobnet"
|
35
|
+
when Tengine::Job::JobnetActual then element_type = self.script_executable? ? "job" :
|
36
|
+
self.jobnet_type_key == :normal ? "jobnet" : self.jobnet_type_name
|
37
|
+
end
|
38
|
+
Tengine.logger.debug("#{element_type} phase changed. <#{ self.id.to_s}> #{self.phase_name} -> #{ self.class.phase_name_by_key(phase_key)}")
|
39
|
+
if is_a?(Tengine::Job::JobnetActual)
|
40
|
+
children.each{|child| child.phase_key = phase_key if child.respond_to?(:chained_box?) && child.chained_box?}
|
41
|
+
end
|
42
|
+
self.write_attribute(:phase_cd, self.class.phase_id_by_key(phase_key))
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
unless defined?(HUMAN_PHASE_KEYS_HASH)
|
47
|
+
HUMAN_PHASE_KEYS_HASH = {
|
48
|
+
'user_stop' => { :dying => :stopping_by_user, :error => :stopped_by_user }.freeze,
|
49
|
+
'timeout' => { :dying => :stopping_by_timeout, :error => :stopped_by_timeout }.freeze,
|
50
|
+
}.freeze
|
51
|
+
|
52
|
+
HUMAN_PHASE_KEYS_ADDITIONAL = HUMAN_PHASE_KEYS_HASH.values.map{|hash| hash.values}.flatten.freeze
|
53
|
+
# HUMAN_PHASE_KEYS = (phase_keys + HUMAN_PHASE_KEYS_ADDITIONAL).freeze
|
54
|
+
end
|
55
|
+
|
56
|
+
# 可読可能なphase_keyを返します。
|
57
|
+
# 具体的にはphase_keyが:dying、:errorの場合は、stop_reasonを考慮した値を返します。
|
58
|
+
def human_phase_key
|
59
|
+
case phase_key
|
60
|
+
when :dying, :error then
|
61
|
+
hash = HUMAN_PHASE_KEYS_HASH[self.stop_reason]
|
62
|
+
hash ? hash[phase_key] : phase_key
|
63
|
+
else phase_key
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# human_phase_keyの表示用の文字列を返します。
|
68
|
+
def human_phase_name
|
69
|
+
I18n.t(human_phase_key, :scope => "selectable_attrs.tengine/job/jobnet_actual.human_phase_name")
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'tengine/core'
|
3
|
+
|
4
|
+
class Tengine::Job::Execution
|
5
|
+
include Mongoid::Document
|
6
|
+
include Mongoid::Timestamps
|
7
|
+
include Tengine::Job::Executable
|
8
|
+
include Tengine::Core::CollectionAccessible
|
9
|
+
|
10
|
+
field :target_actual_ids, :type => Array
|
11
|
+
array_text_accessor :target_actual_ids
|
12
|
+
|
13
|
+
field :preparation_command, :type => String
|
14
|
+
field :actual_base_timeout_alert, :type => Integer
|
15
|
+
field :actual_base_timeout_termination, :type => Integer
|
16
|
+
field :estimated_time, :type => Integer
|
17
|
+
field :keeping_stdout, :type => Boolean
|
18
|
+
field :keeping_stderr, :type => Boolean
|
19
|
+
|
20
|
+
# 1.0.0で想定している実行は 再実行でない実行時にスポット実行は想定していないが
|
21
|
+
# そういう利用も考えられるので、対応できるように属性はわけておきます
|
22
|
+
field :retry, :type => Boolean, :default => false # 再実行かどうか
|
23
|
+
field :spot , :type => Boolean, :default => false # スポット実行かどうか
|
24
|
+
|
25
|
+
belongs_to :root_jobnet, :class_name => "Tengine::Job::RootJobnetActual", :index => true, :inverse_of => :executions
|
26
|
+
|
27
|
+
attr_accessor :signal # runを実行して、ackを返す際に一時的にsignalを記録しておく属性です。それ以外には使用しないでください。
|
28
|
+
|
29
|
+
# 実開始日時から求める予定終了時刻
|
30
|
+
def actual_estimated_end
|
31
|
+
return nil unless started_at
|
32
|
+
(started_at + (estimated_time || 0)).utc
|
33
|
+
end
|
34
|
+
|
35
|
+
def name_as_resource
|
36
|
+
root_jobnet.name_as_resource.sub(/^job:/, 'execution:')
|
37
|
+
end
|
38
|
+
|
39
|
+
def target_actuals
|
40
|
+
r = self.root_jobnet
|
41
|
+
if target_actual_ids.nil? || target_actual_ids.empty?
|
42
|
+
[r]
|
43
|
+
else
|
44
|
+
target_actual_ids.map do |target_actual_id|
|
45
|
+
r.vertex(target_actual_id)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def scope_root
|
51
|
+
unless @scope_root
|
52
|
+
actual = target_actuals.first
|
53
|
+
@scope_root = spot ? actual : actual.parent || actual
|
54
|
+
unless @scope_root
|
55
|
+
raise "@scope_root must not be nil"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
@scope_root
|
59
|
+
end
|
60
|
+
|
61
|
+
def in_scope?(vertex)
|
62
|
+
return false if vertex.nil?
|
63
|
+
return true if target_actual_ids.nil? || target_actual_ids.empty?
|
64
|
+
(vertex.id == scope_root.id) || vertex.ancestors.map(&:id).include?(scope_root.id)
|
65
|
+
end
|
66
|
+
|
67
|
+
def transmit(signal)
|
68
|
+
case phase_key
|
69
|
+
when :initialized then
|
70
|
+
if self.retry
|
71
|
+
target_actuals.each do |target|
|
72
|
+
target.reset(signal)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
self.phase_key = :ready
|
76
|
+
activate(signal)
|
77
|
+
else
|
78
|
+
raise "Unsupported phase_key for transmit: #{phase_key.inspect}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def activate(signal)
|
83
|
+
case phase_key
|
84
|
+
when :ready then
|
85
|
+
self.phase_key = :starting
|
86
|
+
if self.retry
|
87
|
+
target_actuals.each do |target|
|
88
|
+
target.transmit(signal)
|
89
|
+
end
|
90
|
+
else
|
91
|
+
root_jobnet.transmit(signal)
|
92
|
+
end
|
93
|
+
else
|
94
|
+
raise "Unsupported phase_key for activate: #{phase_key.inspect}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def ack(signal)
|
99
|
+
case phase_key
|
100
|
+
when :ready then
|
101
|
+
raise Tengine::Job::Executable::PhaseError, "ack not available on #{phase_key.inspect}"
|
102
|
+
when :starting then
|
103
|
+
self.phase_key = :running
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def succeed(signal)
|
108
|
+
case phase_key
|
109
|
+
when :initialized, :ready, :error then
|
110
|
+
raise Tengine::Job::Executable::PhaseError, "succeed not available on #{phase_key.inspect}"
|
111
|
+
when :starting, :running, :dying, :stuck then
|
112
|
+
self.phase_key = :success
|
113
|
+
signal.fire(self, :"success.execution.job.tengine")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def fail(signal)
|
118
|
+
case phase_key
|
119
|
+
when :initialized, :ready, :success then
|
120
|
+
raise Tengine::Job::Executable::PhaseError, "fail not available on #{phase_key.inspect}"
|
121
|
+
when :starting, :running, :dying, :stuck then
|
122
|
+
self.phase_key = :error
|
123
|
+
signal.fire(self, :"error.execution.job.tengine")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# def fire_stop(signal)
|
128
|
+
# return if self.phase_key == :initialized
|
129
|
+
# signal.fire(self, :"stop.execution.job.tengine", {
|
130
|
+
# :execution_id => self.id,
|
131
|
+
# :root_jobnet_id => root_jobnet.id,
|
132
|
+
# :target_jobnet_id => root_jobnet.id,
|
133
|
+
# })
|
134
|
+
# end
|
135
|
+
|
136
|
+
def stop(signal)
|
137
|
+
self.phase_key = :dying
|
138
|
+
root_jobnet.fire_stop(signal)
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'tengine/job'
|
3
|
+
|
4
|
+
# ルートジョブネットを他のジョブネット内に展開するための特殊なテンプレート用Vertex。
|
5
|
+
class Tengine::Job::Expansion < Tengine::Job::Job
|
6
|
+
def actual_class
|
7
|
+
Tengine::Job::JobnetActual
|
8
|
+
end
|
9
|
+
def root_jobnet_template
|
10
|
+
unless @root_jobnet_template
|
11
|
+
cond = {:dsl_version => root.dsl_version, :name => name}
|
12
|
+
@root_jobnet_template = Tengine::Job::RootJobnetTemplate.first(:conditions => cond)
|
13
|
+
end
|
14
|
+
@root_jobnet_template
|
15
|
+
end
|
16
|
+
|
17
|
+
IGNORED_FIELD_NAMES = (Tengine::Job::Vertex::IGNORED_FIELD_NAMES + %w[name dsl_version jobnet_type_cd version updated_at created_at children edges]).freeze
|
18
|
+
|
19
|
+
def generating_attrs
|
20
|
+
result = super
|
21
|
+
attrs = root_jobnet_template.attributes.dup
|
22
|
+
if template = root_jobnet_template
|
23
|
+
attrs[:template_id] = template.id
|
24
|
+
end
|
25
|
+
attrs.delete_if{|attr, value| IGNORED_FIELD_NAMES.include?(attr)}
|
26
|
+
result.update(attrs)
|
27
|
+
result
|
28
|
+
end
|
29
|
+
def generating_children; root_jobnet_template.children; end
|
30
|
+
def generating_edges; root_jobnet_template.edges; end
|
31
|
+
|
32
|
+
def generate(klass = actual_class)
|
33
|
+
result = super
|
34
|
+
result.was_expansion = true
|
35
|
+
result
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'tengine/job'
|
3
|
+
|
4
|
+
# 処理を意味するVertex。実際に実行を行うTengine::Job::Scriptやジョブネットである
|
5
|
+
# Tengine::Job::Jobnetの継承元である。
|
6
|
+
class Tengine::Job::Job < Tengine::Job::Vertex
|
7
|
+
include Tengine::Job::Connectable
|
8
|
+
include Tengine::Job::Killing
|
9
|
+
|
10
|
+
field :name, :type => String # ジョブの名称。
|
11
|
+
|
12
|
+
validates :name, :presence => true
|
13
|
+
|
14
|
+
# リソース識別子を返します
|
15
|
+
def name_as_resource
|
16
|
+
@name_as_resource ||= "job:#{Tengine::Event.host_name}/#{Process.pid.to_s}/#{root.id.to_s}/#{id.to_s}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def short_inspect
|
20
|
+
"#<%%%-30s id: %s name: %s>" % [self.class.name, self.id.to_s, name]
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'tengine/job'
|
3
|
+
|
4
|
+
require 'selectable_attr'
|
5
|
+
|
6
|
+
# ジョブの始端から終端までを持ち、VertexとEdgeを組み合わせてジョブネットを構成することができるVertex。
|
7
|
+
# 自身もジョブネットを構成するVertexの一部として扱われる。
|
8
|
+
class Tengine::Job::Jobnet < Tengine::Job::Job
|
9
|
+
include Tengine::Core::SelectableAttr
|
10
|
+
include Tengine::Job::ElementSelectorNotation
|
11
|
+
|
12
|
+
autoload :Builder, "tengine/job/jobnet/builder"
|
13
|
+
autoload :StateTransition, 'tengine/job/jobnet/state_transition'
|
14
|
+
autoload :JobStateTransition, 'tengine/job/jobnet/job_state_transition'
|
15
|
+
autoload :JobnetStateTransition, 'tengine/job/jobnet/jobnet_state_transition'
|
16
|
+
|
17
|
+
field :script , :type => String # 実行されるスクリプト(本来Tengine::Job::Scriptが保持しますが、子要素を保持してかつスクリプトを実行するhadoop_job_runもある)
|
18
|
+
field :description , :type => String # ジョブネットの説明
|
19
|
+
field :jobnet_type_cd, :type => Integer, :default => 1 # ジョブネットの種類。後述の定義を参照してください。
|
20
|
+
|
21
|
+
selectable_attr :jobnet_type_cd do
|
22
|
+
entry 1, :normal , "normal"
|
23
|
+
entry 2, :finally , "finally", :alternative => true
|
24
|
+
# entry 3, :recover , "recover", :alternative => true
|
25
|
+
entry 4, :hadoop_job_run, "hadoop job run"
|
26
|
+
entry 5, :hadoop_job , "hadoop job" , :chained_box => true
|
27
|
+
entry 6, :map_phase , "map phase" , :chained_box => true
|
28
|
+
entry 7, :reduce_phase , "reduce phase" , :chained_box => true
|
29
|
+
end
|
30
|
+
def chained_box?; jobnet_type_entry[:chained_box]; end
|
31
|
+
|
32
|
+
embeds_many :edges, :class_name => "Tengine::Job::Edge", :inverse_of => :owner
|
33
|
+
|
34
|
+
class << self
|
35
|
+
def by_name(name)
|
36
|
+
first(:conditions => {:name => name})
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def script_executable?
|
41
|
+
!script.blank?
|
42
|
+
end
|
43
|
+
|
44
|
+
def start_vertex
|
45
|
+
self.children.detect{|child| child.is_a?(Tengine::Job::Start)}
|
46
|
+
end
|
47
|
+
|
48
|
+
def end_vertex
|
49
|
+
self.children.detect{|child| child.is_a?(Tengine::Job::End)}
|
50
|
+
end
|
51
|
+
|
52
|
+
def finally_vertex
|
53
|
+
self.children.detect{|child| child.is_a?(Tengine::Job::Jobnet) && (child.jobnet_type_key == :finally)}
|
54
|
+
end
|
55
|
+
alias_method :finally_jobnet, :finally_vertex
|
56
|
+
|
57
|
+
def with_start
|
58
|
+
self.children << Tengine::Job::Start.new
|
59
|
+
self
|
60
|
+
end
|
61
|
+
|
62
|
+
def prepare_end
|
63
|
+
if self.children.last.is_a?(Tengine::Job::End)
|
64
|
+
_end = self.children.last
|
65
|
+
yield(_end) if block_given?
|
66
|
+
else
|
67
|
+
_end = Tengine::Job::End.new
|
68
|
+
yield(_end) if block_given?
|
69
|
+
self.children << _end
|
70
|
+
end
|
71
|
+
_end
|
72
|
+
end
|
73
|
+
|
74
|
+
def child_by_name(str)
|
75
|
+
case str
|
76
|
+
when '..' then parent
|
77
|
+
when '.' then self
|
78
|
+
when 'start' then start_vertex
|
79
|
+
when 'end' then end_vertex
|
80
|
+
when 'finally' then finally_vertex
|
81
|
+
else
|
82
|
+
self.children.detect{|c| c.is_a?(Tengine::Job::Job) && (c.name == str)}
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def build_edges(auto_sequence, boot_job_names, redirections)
|
87
|
+
if self.children.length == 1 # 最初に追加したStartだけなら。
|
88
|
+
self.children.delete_all
|
89
|
+
return
|
90
|
+
end
|
91
|
+
if auto_sequence || boot_job_names.empty?
|
92
|
+
prepare_end
|
93
|
+
build_sequencial_edges
|
94
|
+
else
|
95
|
+
Builder.new(self, boot_job_names, redirections).process
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def build_sequencial_edges
|
100
|
+
self.edges.clear
|
101
|
+
current = nil
|
102
|
+
self.children.each do |child|
|
103
|
+
next if child.is_a?(Tengine::Job::Jobnet) && !!child.jobnet_type_entry[:alternative]
|
104
|
+
if current
|
105
|
+
edge = self.new_edge(current, child)
|
106
|
+
yield(edge) if block_given?
|
107
|
+
end
|
108
|
+
current = child
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def new_edge(origin, destination)
|
113
|
+
origin_id = origin.is_a?(Tengine::Job::Vertex) ? origin.id : origin
|
114
|
+
destination_id = destination.is_a?(Tengine::Job::Vertex) ? destination.id : destination
|
115
|
+
edges.new(:origin_id => origin_id, :destination_id => destination_id)
|
116
|
+
end
|
117
|
+
|
118
|
+
def find_descendant_edge(edge_id)
|
119
|
+
edge_id = String(edge_id)
|
120
|
+
visitor = Tengine::Job::Vertex::AnyVisitor.new do |vertex|
|
121
|
+
if vertex.respond_to?(:edges)
|
122
|
+
vertex.edges.detect{|edge| edge.id.to_s == edge_id}
|
123
|
+
else
|
124
|
+
nil
|
125
|
+
end
|
126
|
+
end
|
127
|
+
visitor.visit(self)
|
128
|
+
end
|
129
|
+
alias_method :edge, :find_descendant_edge
|
130
|
+
|
131
|
+
def find_descendant(vertex_id)
|
132
|
+
vertex_id = String(vertex_id)
|
133
|
+
return nil if vertex_id == self.id.to_s
|
134
|
+
vertex(vertex_id)
|
135
|
+
end
|
136
|
+
|
137
|
+
def vertex(vertex_id)
|
138
|
+
vertex_id = String(vertex_id)
|
139
|
+
return self if vertex_id == self.id.to_s
|
140
|
+
visitor = Tengine::Job::Vertex::AnyVisitor.new{|v| vertex_id == v.id.to_s ? v : nil }
|
141
|
+
visitor.visit(self)
|
142
|
+
end
|
143
|
+
|
144
|
+
def find_descendant_by_name_path(name_path)
|
145
|
+
return nil if name_path == self.name_path
|
146
|
+
vertex_by_name_path(name_path)
|
147
|
+
end
|
148
|
+
|
149
|
+
def vertex_by_name_path(name_path)
|
150
|
+
Tengine::Job::NamePath.absolute?(name_path) ?
|
151
|
+
root.vertex_by_absolute_name_path(name_path) :
|
152
|
+
vertex_by_relative_name_path(name_path)
|
153
|
+
end
|
154
|
+
|
155
|
+
def vertex_by_absolute_name_path(name_path)
|
156
|
+
return self if name_path.to_s == self.name_path
|
157
|
+
visitor = Tengine::Job::Vertex::AnyVisitor.new do |vertex|
|
158
|
+
if name_path == (vertex.respond_to?(:name_path) ? vertex.name_path : nil)
|
159
|
+
vertex
|
160
|
+
else
|
161
|
+
nil
|
162
|
+
end
|
163
|
+
end
|
164
|
+
visitor.visit(self)
|
165
|
+
end
|
166
|
+
|
167
|
+
def vertex_by_relative_name_path(name_path)
|
168
|
+
head, tail = *name_path.split(Tengine::Job::NamePath::SEPARATOR, 2)
|
169
|
+
child = child_by_name(head)
|
170
|
+
tail ? child.vertex_by_relative_name_path(tail) : child
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|