tengine_job 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +15 -0
  2. data/Gemfile.lock +78 -48
  3. data/bin/tengine_job +71 -0
  4. data/examples/0004_retry_one_layer.rb +10 -7
  5. data/examples/0027_parallel_ssh_job +9 -0
  6. data/examples/0027_parallel_ssh_jobs.rb +14 -0
  7. data/lib/tengine/job.rb +19 -49
  8. data/lib/tengine/job/dsl.rb +13 -0
  9. data/lib/tengine/job/{dsl_binder.rb → dsl/binder.rb} +4 -4
  10. data/lib/tengine/job/{dsl_evaluator.rb → dsl/evaluator.rb} +2 -2
  11. data/lib/tengine/job/{dsl_loader.rb → dsl/loader.rb} +20 -22
  12. data/lib/tengine/job/runtime.rb +32 -0
  13. data/lib/tengine/job/{drivers → runtime/drivers}/job_control_driver.rb +46 -92
  14. data/lib/tengine/job/{drivers → runtime/drivers}/job_execution_driver.rb +14 -10
  15. data/lib/tengine/job/runtime/drivers/jobnet_control_driver.rb +240 -0
  16. data/lib/tengine/job/{drivers → runtime/drivers}/schedule_driver.rb +4 -4
  17. data/lib/tengine/job/{edge.rb → runtime/edge.rb} +79 -25
  18. data/lib/tengine/job/{executable.rb → runtime/executable.rb} +35 -15
  19. data/lib/tengine/job/{execution.rb → runtime/execution.rb} +19 -11
  20. data/lib/tengine/job/runtime/job_base.rb +5 -0
  21. data/lib/tengine/job/runtime/jobnet.rb +283 -0
  22. data/lib/tengine/job/runtime/junction.rb +44 -0
  23. data/lib/tengine/job/runtime/named_vertex.rb +95 -0
  24. data/lib/tengine/job/runtime/root_jobnet.rb +81 -0
  25. data/lib/tengine/job/{signal.rb → runtime/signal.rb} +99 -13
  26. data/lib/tengine/job/runtime/ssh_job.rb +486 -0
  27. data/lib/tengine/job/{jobnet → runtime}/state_transition.rb +6 -4
  28. data/lib/tengine/job/runtime/stoppable.rb +64 -0
  29. data/lib/tengine/job/runtime/vertex.rb +50 -0
  30. data/lib/tengine/job/structure.rb +20 -0
  31. data/lib/tengine/job/{category.rb → structure/category.rb} +9 -5
  32. data/lib/tengine/job/{jobnet/builder.rb → structure/edge_builder.rb} +11 -7
  33. data/lib/tengine/job/{element_selector_notation.rb → structure/element_selector_notation.rb} +15 -11
  34. data/lib/tengine/job/structure/jobnet_builder.rb +83 -0
  35. data/lib/tengine/job/structure/jobnet_finder.rb +60 -0
  36. data/lib/tengine/job/{name_path.rb → structure/name_path.rb} +2 -2
  37. data/lib/tengine/job/structure/tree.rb +20 -0
  38. data/lib/tengine/job/structure/visitor.rb +67 -0
  39. data/lib/tengine/job/template.rb +24 -0
  40. data/lib/tengine/job/template/edge.rb +37 -0
  41. data/lib/tengine/job/template/expansion.rb +24 -0
  42. data/lib/tengine/job/template/generator.rb +111 -0
  43. data/lib/tengine/job/template/jobnet.rb +83 -0
  44. data/lib/tengine/job/template/junction.rb +14 -0
  45. data/lib/tengine/job/{job.rb → template/named_vertex.rb} +3 -5
  46. data/lib/tengine/job/{root_jobnet_template.rb → template/root_jobnet.rb} +12 -26
  47. data/lib/tengine/job/template/ssh_job.rb +80 -0
  48. data/lib/tengine/job/template/vertex.rb +97 -0
  49. metadata +127 -93
  50. data/lib/tengine/job/connectable.rb +0 -43
  51. data/lib/tengine/job/drivers/jobnet_control_driver.rb +0 -249
  52. data/lib/tengine/job/end.rb +0 -32
  53. data/lib/tengine/job/expansion.rb +0 -37
  54. data/lib/tengine/job/fork.rb +0 -6
  55. data/lib/tengine/job/jobnet.rb +0 -184
  56. data/lib/tengine/job/jobnet/job_state_transition.rb +0 -167
  57. data/lib/tengine/job/jobnet/jobnet_state_transition.rb +0 -110
  58. data/lib/tengine/job/jobnet_actual.rb +0 -84
  59. data/lib/tengine/job/jobnet_template.rb +0 -10
  60. data/lib/tengine/job/join.rb +0 -6
  61. data/lib/tengine/job/junction.rb +0 -29
  62. data/lib/tengine/job/killing.rb +0 -30
  63. data/lib/tengine/job/mm_compatibility.rb +0 -6
  64. data/lib/tengine/job/mm_compatibility/connectable.rb +0 -13
  65. data/lib/tengine/job/root.rb +0 -16
  66. data/lib/tengine/job/root_jobnet_actual.rb +0 -58
  67. data/lib/tengine/job/script_executable.rb +0 -235
  68. data/lib/tengine/job/start.rb +0 -20
  69. data/lib/tengine/job/stoppable.rb +0 -15
  70. data/lib/tengine/job/vertex.rb +0 -181
@@ -1,43 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- require 'tengine/job'
3
-
4
- require 'tengine_resource'
5
-
6
- module Tengine::Job::Connectable
7
- extend ActiveSupport::Concern
8
-
9
- included do
10
- field :server_name , :type => String # 接続先となるサーバ名。Tengine::Resource::Server#name を指定します
11
- field :credential_name, :type => String # 接続時に必要な認証情報。Tengine::Resource::Credential#name を指定します
12
-
13
- include Tengine::Job::MmCompatibility::Connectable
14
-
15
- def actual_credential_name
16
- credential_name || (parent ? parent.actual_credential_name : nil)
17
- end
18
-
19
- def actual_server_name
20
- server_name || (parent ? parent.actual_server_name : nil)
21
- end
22
-
23
- def actual_credential
24
- key = actual_credential_name
25
- return nil if key.blank?
26
- result = Tengine::Resource::Credential.where({:name => key}).first
27
- # TODO 使用する例外クラスはこれで良いのか検討
28
- raise Mongoid::Errors::DocumentNotFound.new(Tengine::Resource::Credential, key, []) unless result
29
- result
30
- end
31
-
32
- def actual_server
33
- key = actual_server_name
34
- return nil if key.blank?
35
- result = Tengine::Resource::Server.where({:name => key}).first
36
- # TODO 使用する例外クラスはこれで良いのか検討
37
- raise Mongoid::Errors::DocumentNotFound.new(Tengine::Resource::Server, key, []) unless result
38
- result
39
- end
40
-
41
-
42
- end
43
- end
@@ -1,249 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- include Tengine::Core::SafeUpdatable
3
-
4
- [
5
- :'start.jobnet.job.tengine',
6
- :'success.job.job.tengine',
7
- :'error.job.job.tengine',
8
- :'success.jobnet.job.tengine',
9
- :'error.jobnet.job.tengine',
10
- :'stop.jobnet.job.tengine',
11
- ].each do |i|
12
- ack_policy :after_all_handler_submit, i
13
- end
14
-
15
-
16
- # ジョブネット制御ドライバ
17
- driver :jobnet_control_driver do
18
-
19
- on :'start.jobnet.job.tengine' do
20
- signal = Tengine::Job::Signal.new(event)
21
- root_jobnet = Tengine::Job::RootJobnetActual.find(event[:root_jobnet_id])
22
- root_jobnet.update_with_lock do
23
- signal.reset
24
- target_jobnet = root_jobnet.find_descendant(event[:target_jobnet_id]) || root_jobnet
25
- signal.with_paths_backup do
26
- target_jobnet.activate(signal)
27
- end
28
- end
29
- signal.execution.with(safe: safemode(Tengine::Job::Execution.collection)).save! if event[:root_jobnet_id] == event[:target_jobnet_id]
30
- signal.reservations.each{|r| fire(*r.fire_args)}
31
- submit
32
- end
33
-
34
- on :'start.jobnet.job.tengine.failed.tengined' do
35
- # このイベントは壊れていたからfailedなのかもしれない。多重送信によ
36
- # りfailedなのかもしれない。あまりへんな仮定を置かない方が良い。
37
- e = event
38
- f = e.properties or next
39
- g = f["original_event"] or next
40
- h = g["properties"] or next
41
- i = h["root_jobnet_id"] or next
42
- j = h["target_jobnet_id"] or next
43
- k = Tengine::Job::RootJobnetActual.find(i) or next
44
-
45
- k.update_with_lock do
46
- l = k.find_descendant(j) || k
47
- l.phase_key = :stuck
48
- end
49
- end
50
-
51
- on :'success.job.job.tengine' do
52
- signal = Tengine::Job::Signal.new(event)
53
- root_jobnet = Tengine::Job::RootJobnetActual.find(event[:root_jobnet_id])
54
- root_jobnet.update_with_lock do
55
- signal.reset
56
- target_job = root_jobnet.find_descendant(event[:target_job_id])
57
- signal.with_paths_backup do
58
- edge = target_job.next_edges.first
59
- edge.transmit(signal)
60
- end
61
- end
62
- # (*1)
63
- signal.reservations.each{|r| fire(*r.fire_args)}
64
- submit
65
- end
66
-
67
- on :'success.job.job.tengine.failed.tengined' do
68
- # このイベントは壊れていたからfailedなのかもしれない。多重送信によ
69
- # りfailedなのかもしれない。あまりへんな仮定を置かない方が良い。
70
- e = event
71
- f = e.properties or next
72
- g = f["original_event"] or next
73
- h = g["properties"] or next
74
- i = h["root_jobnet_id"] or next
75
- j = h["target_jobnet_id"] or next
76
- k = h["target_job_id"] or next
77
- l = Tengine::Job::RootJobnetActual.find(i) or next
78
-
79
- # 上記(*1)のポイントでtenginedが落ちた時のことを考えると、後続のエッ
80
- # ジはもうtransmitしているが送信すべきイベントが欠けている状態であ
81
- # るので、この場合このジョブがおかしくなっているというよりむしろジョ
82
- # ブネット全体がおかしくなっているというべきである。
83
- l.update_with_lock do
84
- m = l.find_descendant(j) || l
85
- n = m.find_descendant(k)
86
- o = n.parent || n
87
- o.phase_key = :stuck
88
- end
89
- end
90
-
91
- on :'error.job.job.tengine' do
92
- signal = Tengine::Job::Signal.new(event)
93
- root_jobnet = Tengine::Job::RootJobnetActual.find(event[:root_jobnet_id])
94
- root_jobnet.update_with_lock do
95
- signal.reset
96
- target_job = root_jobnet.vertex(event[:target_job_id])
97
- signal.with_paths_backup do
98
- edge = target_job.next_edges.first
99
- edge.close_followings
100
- edge.transmit(signal)
101
- end
102
- # target_jobnet = target_job.parent
103
- # target_jobnet.jobnet_fail(signal)
104
- end
105
- signal.reservations.each{|r| fire(*r.fire_args)}
106
- submit
107
- end
108
-
109
- on :'error.job.job.tengine.failed.tengined' do
110
- # このイベントは壊れていたからfailedなのかもしれない。多重送信によ
111
- # りfailedなのかもしれない。あまりへんな仮定を置かない方が良い。
112
- e = event
113
- f = e.properties or next
114
- g = f["original_event"] or next
115
- h = g["properties"] or next
116
- i = h["root_jobnet_id"] or next
117
- j = h["target_jobnet_id"] or next
118
- k = h["target_job_id"] or next
119
- l = Tengine::Job::RootJobnetActual.find(i) or next
120
-
121
- # 同上で、この場合このジョブがおかしくなっているというよりむしろジョ
122
- # ブネット全体がおかしくなっているというべきである。
123
- l.update_with_lock do
124
- m = l.find_descendant(j) || l
125
- n = m.find_descendant(k)
126
- o = n.parent || n
127
- o.phase_key = :stuck
128
- end
129
- end
130
-
131
- on :'success.jobnet.job.tengine' do
132
- signal = Tengine::Job::Signal.new(event)
133
- root_jobnet = Tengine::Job::RootJobnetActual.find(event[:root_jobnet_id])
134
- root_jobnet.update_with_lock do
135
- signal.reset
136
- target_jobnet = root_jobnet.vertex(event[:target_jobnet_id])
137
- signal.with_paths_backup do
138
- case target_jobnet.jobnet_type_key
139
- when :finally then
140
- parent = target_jobnet.parent
141
- edge = parent.end_vertex.prev_edges.first
142
- (edge.closed? || edge.closing?) ?
143
- parent.fail(signal) :
144
- parent.succeed(signal)
145
- else
146
- if edge = (target_jobnet.next_edges || []).first
147
- edge.transmit(signal)
148
- else
149
- (target_jobnet.parent || signal.execution).succeed(signal)
150
- end
151
- end
152
- end
153
- end
154
- signal.execution.with(sage: safemode(Tengine::Job::Execution.collection)).save! if event[:root_jobnet_id] == event[:target_jobnet_id]
155
- signal.reservations.each{|r| fire(*r.fire_args)}
156
- submit
157
- end
158
-
159
- on :'success.jobnet.job.tengine.failed.tengined' do
160
- # このイベントは壊れていたからfailedなのかもしれない。多重送信によ
161
- # りfailedなのかもしれない。あまりへんな仮定を置かない方が良い。
162
- e = event
163
- f = e.properties or next
164
- g = f["original_event"] or next
165
- h = g["properties"] or next
166
- i = h["root_jobnet_id"] or next
167
- j = h["target_jobnet_id"] or next
168
- k = Tengine::Job::RootJobnetActual.find(i) or next
169
-
170
- k.update_with_lock do
171
- l = k.find_descendant(j) || k
172
- l.phase_key = :stuck
173
- end
174
- end
175
-
176
- on :'error.jobnet.job.tengine' do
177
- signal = Tengine::Job::Signal.new(event)
178
- root_jobnet = Tengine::Job::RootJobnetActual.find(event[:root_jobnet_id])
179
- root_jobnet.update_with_lock do
180
- signal.reset
181
- target_jobnet = root_jobnet.find_descendant(event[:target_jobnet_id]) || root_jobnet
182
- signal.with_paths_backup do
183
- case target_jobnet.jobnet_type_key
184
- when :finally then
185
- target_jobnet.parent.fail(signal)
186
- else
187
- if edge = (target_jobnet.next_edges || []).first
188
- edge.close_followings
189
- edge.transmit(signal)
190
- else
191
- (target_jobnet.parent || signal.execution).fail(signal)
192
- end
193
- end
194
- end
195
- # if target_parent = target_jobnet.parent
196
- # target_parent.end_vertex.transmit(signal)
197
- # end
198
- end
199
- signal.execution.with(safe: safemode(Tengine::Job::Execution.collection)).save! if event[:root_jobnet_id] == event[:target_jobnet_id]
200
- signal.reservations.each{|r| fire(*r.fire_args)}
201
- submit
202
- end
203
-
204
- on :'error.jobnet.job.tengine.failed.tengined' do
205
- # このイベントは壊れていたからfailedなのかもしれない。多重送信によ
206
- # りfailedなのかもしれない。あまりへんな仮定を置かない方が良い。
207
- e = event
208
- f = e.properties or next
209
- g = f["original_event"] or next
210
- h = g["properties"] or next
211
- i = h["root_jobnet_id"] or next
212
- j = h["target_jobnet_id"] or next
213
- k = Tengine::Job::RootJobnetActual.find(i) or next
214
-
215
- k.update_with_lock do
216
- l = k.find_descendant(j) || k
217
- l.phase_key = :stuck
218
- end
219
- end
220
-
221
- on :'stop.jobnet.job.tengine' do
222
- signal = Tengine::Job::Signal.new(event)
223
- root_jobnet = Tengine::Job::RootJobnetActual.find(event[:root_jobnet_id])
224
- root_jobnet.update_with_lock do
225
- signal.reset
226
- target_jobnet = root_jobnet.find_descendant(event[:target_jobnet_id]) || root_jobnet
227
- target_jobnet.stop(signal)
228
- end
229
- signal.reservations.each{|r| fire(*r.fire_args) }
230
- submit
231
- end
232
-
233
- on :'stop.jobnet.job.tengine.failed.tengined' do
234
- # このイベントは壊れていたからfailedなのかもしれない。多重送信によ
235
- # りfailedなのかもしれない。あまりへんな仮定を置かない方が良い。
236
- e = event
237
- f = e.properties or next
238
- g = f["original_event"] or next
239
- h = g["properties"] or next
240
- i = h["root_jobnet_id"] or next
241
- j = h["target_jobnet_id"] or next
242
- k = Tengine::Job::RootJobnetActual.find(i) or next
243
-
244
- k.update_with_lock do
245
- l = k.find_descendant(j) || k
246
- l.phase_key = :stuck
247
- end
248
- end
249
- end
@@ -1,32 +0,0 @@
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) unless parent.phase_key == :stuck
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
@@ -1,37 +0,0 @@
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.where(cond).first
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
@@ -1,6 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- require 'tengine/job'
3
-
4
- # 一つのVertexから複数のVertexへSignalを通知する分岐のVertex。
5
- class Tengine::Job::Fork < Tengine::Job::Junction
6
- end
@@ -1,184 +0,0 @@
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
- include Tengine::Core::SafeUpdatable
12
-
13
- autoload :Builder, "tengine/job/jobnet/builder"
14
- autoload :StateTransition, 'tengine/job/jobnet/state_transition'
15
- autoload :JobStateTransition, 'tengine/job/jobnet/job_state_transition'
16
- autoload :JobnetStateTransition, 'tengine/job/jobnet/jobnet_state_transition'
17
-
18
- field :script , :type => String # 実行されるスクリプト(本来Tengine::Job::Scriptが保持しますが、子要素を保持してかつスクリプトを実行するhadoop_job_runもある)
19
- field :description , :type => String # ジョブネットの説明
20
- field :jobnet_type_cd, :type => Integer, :default => 1 # ジョブネットの種類。後述の定義を参照してください。
21
-
22
- selectable_attr :jobnet_type_cd do
23
- entry 1, :normal , "normal"
24
- entry 2, :finally , "finally", :alternative => true
25
- # entry 3, :recover , "recover", :alternative => true
26
- entry 4, :hadoop_job_run, "hadoop job run"
27
- entry 5, :hadoop_job , "hadoop job" , :chained_box => true
28
- entry 6, :map_phase , "map phase" , :chained_box => true
29
- entry 7, :reduce_phase , "reduce phase" , :chained_box => true
30
- end
31
- def chained_box?; jobnet_type_entry[:chained_box]; end
32
-
33
- embeds_many :edges, :class_name => "Tengine::Job::Edge", :inverse_of => :owner , :validate => false
34
-
35
- before_validation do |r|
36
- r.edges.each do |edge|
37
- unless edge.valid?
38
- edge.errors.each do |f, error|
39
- r.errors.add(:base, "#{edge.name_for_message} #{f.to_s.humanize} #{error}")
40
- end
41
- end
42
- end
43
- end
44
-
45
- class << self
46
- def by_name(name)
47
- where({:name => name}).first
48
- end
49
- end
50
-
51
- def script_executable?
52
- !script.blank?
53
- end
54
-
55
- def start_vertex
56
- self.children.detect{|child| child.is_a?(Tengine::Job::Start)}
57
- end
58
-
59
- def end_vertex
60
- self.children.detect{|child| child.is_a?(Tengine::Job::End)}
61
- end
62
-
63
- def finally_vertex
64
- self.children.detect{|child| child.is_a?(Tengine::Job::Jobnet) && (child.jobnet_type_key == :finally)}
65
- end
66
- alias_method :finally_jobnet, :finally_vertex
67
-
68
- def with_start
69
- self.children << Tengine::Job::Start.new
70
- self
71
- end
72
-
73
- def prepare_end
74
- if self.children.last.is_a?(Tengine::Job::End)
75
- _end = self.children.last
76
- yield(_end) if block_given?
77
- else
78
- _end = Tengine::Job::End.new
79
- yield(_end) if block_given?
80
- self.children << _end
81
- end
82
- _end
83
- end
84
-
85
- def child_by_name(str)
86
- case str
87
- when '..' then parent
88
- when '.' then self
89
- when 'start' then start_vertex
90
- when 'end' then end_vertex
91
- when 'finally' then finally_vertex
92
- else
93
- self.children.detect{|c| c.is_a?(Tengine::Job::Job) && (c.name == str)}
94
- end
95
- end
96
-
97
- def build_edges(auto_sequence, boot_job_names, redirections)
98
- if self.children.length == 1 # 最初に追加したStartだけなら。
99
- self.children.delete_all
100
- return
101
- end
102
- if auto_sequence || boot_job_names.empty?
103
- prepare_end
104
- build_sequencial_edges
105
- else
106
- Builder.new(self, boot_job_names, redirections).process
107
- end
108
- end
109
-
110
- def build_sequencial_edges
111
- self.edges.clear
112
- current = nil
113
- self.children.each do |child|
114
- next if child.is_a?(Tengine::Job::Jobnet) && !!child.jobnet_type_entry[:alternative]
115
- if current
116
- edge = self.new_edge(current, child)
117
- yield(edge) if block_given?
118
- end
119
- current = child
120
- end
121
- end
122
-
123
- def new_edge(origin, destination)
124
- origin_id = origin.is_a?(Tengine::Job::Vertex) ? origin.id : origin
125
- destination_id = destination.is_a?(Tengine::Job::Vertex) ? destination.id : destination
126
- edges.new(:origin_id => origin_id, :destination_id => destination_id)
127
- end
128
-
129
- def find_descendant_edge(edge_id)
130
- edge_id = String(edge_id)
131
- visitor = Tengine::Job::Vertex::AnyVisitor.new do |vertex|
132
- if vertex.respond_to?(:edges)
133
- vertex.edges.detect{|edge| edge.id.to_s == edge_id}
134
- else
135
- nil
136
- end
137
- end
138
- visitor.visit(self)
139
- end
140
- alias_method :edge, :find_descendant_edge
141
-
142
- def find_descendant(vertex_id)
143
- vertex_id = String(vertex_id)
144
- return nil if vertex_id == self.id.to_s
145
- vertex(vertex_id)
146
- end
147
-
148
- def vertex(vertex_id)
149
- vertex_id = String(vertex_id)
150
- return self if vertex_id == self.id.to_s
151
- visitor = Tengine::Job::Vertex::AnyVisitor.new{|v| vertex_id == v.id.to_s ? v : nil }
152
- visitor.visit(self)
153
- end
154
-
155
- def find_descendant_by_name_path(name_path)
156
- return nil if name_path == self.name_path
157
- vertex_by_name_path(name_path)
158
- end
159
-
160
- def vertex_by_name_path(name_path)
161
- Tengine::Job::NamePath.absolute?(name_path) ?
162
- root.vertex_by_absolute_name_path(name_path) :
163
- vertex_by_relative_name_path(name_path)
164
- end
165
-
166
- def vertex_by_absolute_name_path(name_path)
167
- return self if name_path.to_s == self.name_path
168
- visitor = Tengine::Job::Vertex::AnyVisitor.new do |vertex|
169
- if name_path == (vertex.respond_to?(:name_path) ? vertex.name_path : nil)
170
- vertex
171
- else
172
- nil
173
- end
174
- end
175
- visitor.visit(self)
176
- end
177
-
178
- def vertex_by_relative_name_path(name_path)
179
- head, tail = *name_path.split(Tengine::Job::NamePath::SEPARATOR, 2)
180
- child = child_by_name(head)
181
- tail ? child.vertex_by_relative_name_path(tail) : child
182
- end
183
-
184
- end