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,6 +1,6 @@
1
- require 'tengine/job'
1
+ require 'tengine/job/structure'
2
2
 
3
- module Tengine::Job::NamePath
3
+ module Tengine::Job::Structure::NamePath
4
4
 
5
5
  SEPARATOR = '/'.freeze
6
6
  ABSOLUTE_PATH_REGEXP = /^\//.freeze
@@ -0,0 +1,20 @@
1
+ require 'tengine/job/structure'
2
+
3
+ module Tengine::Job::Structure::Tree
4
+ def root?
5
+ parent.nil?
6
+ end
7
+
8
+ def root
9
+ root? ? self : parent.root
10
+ end
11
+
12
+ def ancestors
13
+ if parent = self.parent
14
+ parent.ancestors + [parent]
15
+ else
16
+ []
17
+ end
18
+ end
19
+
20
+ end
@@ -0,0 +1,67 @@
1
+ require 'tengine/job/structure'
2
+
3
+ module Tengine::Job::Structure::Visitor
4
+ module Accepter
5
+ def accept_visitor(visitor)
6
+ visitor.visit(self)
7
+ end
8
+ end
9
+
10
+ class Any
11
+ def initialize(&block)
12
+ @block = block
13
+ end
14
+ def visit(vertex)
15
+ if result = @block.call(vertex)
16
+ return result
17
+ end
18
+ vertex.children.each do |child|
19
+ if result = child.accept_visitor(self)
20
+ return result
21
+ end
22
+ end
23
+ return nil
24
+ end
25
+ end
26
+
27
+ class All
28
+ def initialize(&block)
29
+ @block = block
30
+ end
31
+
32
+ def visit(vertex)
33
+ @block.call(vertex)
34
+ vertex.children.each do |child|
35
+ child.accept_visitor(self)
36
+ end
37
+ end
38
+ end
39
+
40
+ class AllWithEdge < All
41
+ def visit(obj)
42
+ if obj.respond_to?(:children)
43
+ super(obj)
44
+ else
45
+ @block.call(obj)
46
+ end
47
+ return unless obj.respond_to?(:edges)
48
+ obj.edges.each{|edge| edge.accept_visitor(self)}
49
+ end
50
+ end
51
+
52
+ class TraceEdge
53
+ def initialize(&block)
54
+ @block = block
55
+ end
56
+
57
+ def visit(obj)
58
+ @block.call(obj)
59
+ if obj.respond_to?(:destination)
60
+ obj.destination.accept_visitor(self)
61
+ elsif obj.respond_to?(:next_edges)
62
+ obj.next_edges.each{|edge| edge.accept_visitor(self) }
63
+ end
64
+ end
65
+ end
66
+
67
+ end
@@ -0,0 +1,24 @@
1
+ require 'tengine/job'
2
+
3
+ module Tengine::Job::Template
4
+ autoload :Vertex , "tengine/job/template/vertex"
5
+ autoload :Edge , "tengine/job/template/edge"
6
+
7
+ autoload :NamedVertex , "tengine/job/template/named_vertex"
8
+
9
+ autoload :Jobnet , "tengine/job/template/jobnet"
10
+ autoload :Start , "tengine/job/template/jobnet"
11
+ autoload :End , "tengine/job/template/jobnet"
12
+
13
+ autoload :Junction , "tengine/job/template/junction"
14
+ autoload :Fork , "tengine/job/template/junction"
15
+ autoload :Join , "tengine/job/template/junction"
16
+
17
+ autoload :RootJobnet , "tengine/job/template/root_jobnet"
18
+
19
+ autoload :SshJob , "tengine/job/template/ssh_job"
20
+
21
+ autoload :Expansion , "tengine/job/template/expansion"
22
+
23
+ autoload :Generator , "tengine/job/template/generator"
24
+ end
@@ -0,0 +1,37 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'tengine/job/template'
3
+ require 'selectable_attr'
4
+
5
+ # Vertexとともにジョブネットを構成するグラフの「辺」を表すモデル
6
+ # Tengine::Job::Template::Jobnetにembeddedされます。
7
+ class Tengine::Job::Template::Edge
8
+ include Mongoid::Document
9
+ include Mongoid::Timestamps
10
+ include Tengine::Core::SelectableAttr
11
+ include Tengine::Job::Structure::Visitor::Accepter
12
+
13
+ embedded_in :owner, :class_name => "Tengine::Job::Template::Jobnet", :inverse_of => :edges
14
+
15
+ field :origin_id , :type => Moped::BSON::ObjectId # 辺の遷移元となるvertexのid
16
+ field :destination_id, :type => Moped::BSON::ObjectId # 辺の遷移先となるvertexのid
17
+
18
+ validates :origin_id, :presence => true
19
+ validates :destination_id, :presence => true
20
+
21
+ def origin
22
+ owner.children.detect{|c| c.id == origin_id}
23
+ end
24
+
25
+ def destination
26
+ owner.children.detect{|c| c.id == destination_id}
27
+ end
28
+
29
+ def name_for_message
30
+ "edge(#{id.to_s}) from #{origin ? origin.name_path : 'no origin'} to #{destination ? destination.name_path : 'no destination'}"
31
+ end
32
+
33
+ def inspect
34
+ "#<#{self.class.name} #{name_for_message}>"
35
+ end
36
+
37
+ end
@@ -0,0 +1,24 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'tengine/job/template'
3
+
4
+ # ルートジョブネットを他のジョブネット内に展開するための特殊なテンプレート用Vertex。
5
+ class Tengine::Job::Template::Expansion < Tengine::Job::Template::NamedVertex
6
+ def actual_class
7
+ Tengine::Job::Runtime::Jobnet
8
+ end
9
+
10
+ def root_jobnet_template
11
+ unless @root_jobnet_template
12
+ cond = {:dsl_version => root.dsl_version, :name => name}
13
+ @root_jobnet_template = Tengine::Job::Template::RootJobnet.where(cond).first
14
+ end
15
+ @root_jobnet_template
16
+ end
17
+
18
+ def actual_credential_name
19
+ @root_jobnet_template.actual_credential_name
20
+ end
21
+ def actual_server_name
22
+ @root_jobnet_template.actual_server_name
23
+ end
24
+ end
@@ -0,0 +1,111 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'tengine/job/template'
4
+
5
+ class Tengine::Job::Template::Generator
6
+ def execute(template, options = {})
7
+ @inherited_attrs = {}
8
+ process(template, options)
9
+ end
10
+
11
+ CLASS_MAP = %w[RootJobnet Jobnet Start End Fork Join SshJob].each_with_object({}){|t, d|
12
+ c = "Tengine::Job::Template::#{t}"
13
+ d[c] = c.sub(/Template/, 'Runtime')
14
+ }.update({"Tengine::Job::Template::Expansion" => "Tengine::Job::Runtime::Jobnet"})
15
+
16
+ BASE_IGNORED_FIELD_NAMES = ["_type", "_id"].freeze
17
+ EXPANSION_IGNORED_FIELD_NAMES = (BASE_IGNORED_FIELD_NAMES +
18
+ %w[dsl_version jobnet_type_cd version updated_at created_at children edges]).freeze
19
+
20
+ def expansion?
21
+ @current.is_a?(Tengine::Job::Template::Expansion)
22
+ end
23
+
24
+ def expansion_root
25
+ cond = {:dsl_version => @current.root.dsl_version, :name => @current.name}
26
+ Tengine::Job::Template::RootJobnet.where(cond).first
27
+ end
28
+
29
+ def ignored_fields
30
+ expansion? ?
31
+ EXPANSION_IGNORED_FIELD_NAMES : BASE_IGNORED_FIELD_NAMES
32
+ end
33
+
34
+ def generating_attrs
35
+ field_names = @current.class.fields.keys - ignored_fields
36
+ attrs = field_names.each_with_object({}){|name, d| d[name] = @current.send(name) }
37
+ if expansion?
38
+ attrs[:was_expansion] = true
39
+ if (t = expansion_root)
40
+ attrs[:template_id] = t.id
41
+ end
42
+ else
43
+ if @current.is_a?(Tengine::Job::Template::Jobnet)
44
+ attrs[:template_id] = @current.id
45
+ end
46
+ end
47
+ attrs
48
+ end
49
+
50
+ def generating_children
51
+ expansion? ?
52
+ expansion_root.children : @current.children
53
+ end
54
+
55
+ def generating_edges
56
+ expansion? ?
57
+ expansion_root.edges :
58
+ @current.respond_to?(:edges) ? @current.edges : []
59
+ end
60
+
61
+ def process(template, options)
62
+ @inherited_attrs, inherited_attrs_backup = merge_inherited_attrs, @inherited_attrs
63
+ @current, current_backup = template, @current
64
+ begin
65
+ generate(options)
66
+ ensure
67
+ @current = current_backup
68
+ @inherited_attrs = inherited_attrs_backup
69
+ end
70
+ end
71
+
72
+ def merge_inherited_attrs
73
+ source = @current.nil? ? nil : expansion? ? expansion_root : @current
74
+ return {} if source.nil?
75
+ result = @inherited_attrs.dup
76
+ {
77
+ server_name: source.actual_server_name,
78
+ credential_name: source.actual_credential_name,
79
+ killing_signals: source.actual_killing_signals,
80
+ killing_signal_interval: source.actual_killing_signal_interval,
81
+ }.each do |key, value|
82
+ next if value.blank?
83
+ result[key] = value # sourceからの値が有効なら上書きする
84
+ end
85
+ result
86
+ end
87
+
88
+ def generate(options)
89
+ attrs = generating_attrs.update(child_index: options[:child_index], parent: options[:parent])
90
+ @inherited_attrs.each{|key, value| attrs[key] ||= value }
91
+ klass_name = CLASS_MAP[@current.class.name]
92
+ result = klass_name.constantize.new(attrs)
93
+ result.save!
94
+ src_to_generated = {}
95
+ generating_children.each.with_index do |child, index|
96
+ generated = process(child, child_index: index + 1, parent: result)
97
+ src_to_generated[child.id] = generated.id
98
+ result.children << generated
99
+ end
100
+ generating_edges.each do |edge|
101
+ generated = Tengine::Job::Runtime::Edge.new
102
+ generated.origin_id = src_to_generated[edge.origin_id]
103
+ generated.destination_id = src_to_generated[edge.destination_id]
104
+ result.edges << generated
105
+ end
106
+ yield(result) if block_given? # 派生クラスでsave!の前に処理を入れるためのyield
107
+ result.save!
108
+ result
109
+ end
110
+
111
+ end
@@ -0,0 +1,83 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'tengine/job/template'
3
+
4
+ require 'selectable_attr'
5
+
6
+ # ジョブの始端から終端までを持ち、VertexとEdgeを組み合わせてジョブネットを構成することができるVertex。
7
+ # 自身もジョブネットを構成するVertexの一部として扱われる。
8
+ class Tengine::Job::Template::Jobnet < Tengine::Job::Template::NamedVertex
9
+ include Tengine::Core::SelectableAttr
10
+ include Tengine::Core::SafeUpdatable
11
+
12
+ include Tengine::Job::Structure::JobnetBuilder
13
+ include Tengine::Job::Structure::JobnetFinder
14
+ include Tengine::Job::Structure::ElementSelectorNotation
15
+
16
+ include Tengine::Job::Template::SshJob::Settings
17
+
18
+ autoload :Builder, "tengine/job/jobnet/builder"
19
+ autoload :StateTransition, 'tengine/job/jobnet/state_transition'
20
+ autoload :JobStateTransition, 'tengine/job/jobnet/job_state_transition'
21
+ autoload :JobnetStateTransition, 'tengine/job/jobnet/jobnet_state_transition'
22
+
23
+ field :description , :type => String # ジョブネットの説明
24
+
25
+ field :jobnet_type_cd, :type => Integer, :default => 1 # ジョブネットの種類。後述の定義を参照してください。
26
+
27
+ selectable_attr :jobnet_type_cd do
28
+ entry 1, :normal , "normal"
29
+ entry 2, :finally , "finally", :alternative => true
30
+ # entry 3, :recover , "recover", :alternative => true
31
+ entry 4, :hadoop_job_run, "hadoop job run"
32
+ entry 5, :hadoop_job , "hadoop job" , :chained_box => true
33
+ entry 6, :map_phase , "map phase" , :chained_box => true
34
+ entry 7, :reduce_phase , "reduce phase" , :chained_box => true
35
+ end
36
+ def chained_box?; jobnet_type_entry[:chained_box]; end
37
+
38
+ embeds_many :edges, :class_name => "Tengine::Job::Template::Edge", :inverse_of => :owner , :validate => false
39
+ accepts_nested_attributes_for :edges
40
+
41
+ before_validation do |r|
42
+ r.edges.each do |edge|
43
+ unless edge.valid?
44
+ edge.errors.each do |f, error|
45
+ r.errors.add(:base, "#{edge.name_for_message} #{f.to_s.humanize} #{error}")
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+
52
+ VERTEX_CLASSES = {
53
+ vertex: "Vertex",
54
+ start_vertex: "Start",
55
+ end_vertex: "End",
56
+ jobnet: "Jobnet",
57
+ fork: "Fork",
58
+ join: "Join",
59
+ }.freeze
60
+
61
+ VERTEX_CLASSES.each do |key, value|
62
+ instance_eval("def #{key}_class; Tengine::Job::Template::#{value}; end", __FILE__, __LINE__)
63
+ end
64
+
65
+ class << self
66
+ def by_name(name)
67
+ where({:name => name}).first
68
+ end
69
+
70
+ end
71
+ end
72
+
73
+
74
+
75
+
76
+ # ジョブネットの始端を表すVertex。特に状態は持たない。
77
+ class Tengine::Job::Template::Start < Tengine::Job::Template::Vertex
78
+ end
79
+
80
+
81
+ # ジョブネットの終端を表すVertex。特に状態は持たない。
82
+ class Tengine::Job::Template::End < Tengine::Job::Template::Vertex
83
+ end
@@ -0,0 +1,14 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'tengine/job/template'
3
+
4
+ # ForkやJoinの継承元となるVertex。特に状態は持たない。
5
+ class Tengine::Job::Template::Junction < Tengine::Job::Template::Vertex
6
+ end
7
+
8
+ # 一つのVertexから複数のVertexへSignalを通知する分岐のVertex。
9
+ class Tengine::Job::Template::Fork < Tengine::Job::Template::Junction
10
+ end
11
+
12
+ # 複数のVertexの終了を待ちあわせて一つのVertexへSignalを通知する合流のVertex。
13
+ class Tengine::Job::Template::Join < Tengine::Job::Template::Junction
14
+ end
@@ -1,11 +1,9 @@
1
1
  # -*- coding: utf-8 -*-
2
- require 'tengine/job'
2
+ require 'tengine/job/template'
3
3
 
4
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
5
+ # Tengine::Job::Template::Jobnetの継承元である。
6
+ class Tengine::Job::Template::NamedVertex < Tengine::Job::Template::Vertex
9
7
 
10
8
  field :name, :type => String # ジョブの名称。
11
9
 
@@ -1,39 +1,20 @@
1
1
  # -*- coding: utf-8 -*-
2
- require 'tengine/job'
2
+ require 'tengine/job/template'
3
3
 
4
4
  # DSLを評価して登録されるルートジョブネットを表すVertex
5
- class Tengine::Job::RootJobnetTemplate < Tengine::Job::JobnetTemplate
6
- include Tengine::Job::Root
5
+ class Tengine::Job::Template::RootJobnet < Tengine::Job::Template::Jobnet
7
6
  include Tengine::Core::FindByName
8
7
 
9
8
  field :dsl_filepath, :type => String # ルートジョブネットを定義した際にロードされたDSLのファイル名(Tengine::Core::Config#dsl_dir_pathからの相対パス)
10
9
  field :dsl_lineno , :type => Integer # ルートジョブネットを定義するjobnetメソッドの呼び出しの、ロードされたDSLのファイルでの行番号
11
10
  field :dsl_version , :type => String # ルートジョブネットを定義した際のDSLのバージョン
12
11
 
13
- def actual_class
14
- Tengine::Job::RootJobnetActual
15
- end
16
- def generate(klass = actual_class)
17
- result = super(klass)
18
- result.template = self
19
- result
20
- end
12
+ belongs_to :category, inverse_of: nil, index: true, class_name: "Tengine::Job::Structure::Category"
21
13
 
22
- def execute(options = {})
23
- event_sender = options.delete(:sender) || Tengine::Event.default_sender
24
- actual = generate
25
- actual.with(safe: safemode(actual.class.collection)).save!
26
- result = Tengine::Job::Execution.with(
27
- safe: safemode(Tengine::Job::Execution.collection)
28
- ).create!(
29
- (options || {}).update(:root_jobnet_id => actual.id)
30
- )
31
- event_sender.fire(:"start.execution.job.tengine", :properties => {
32
- :execution_id => result.id,
33
- :root_jobnet_id => actual.id,
34
- :target_jobnet_id => actual.id
35
- })
36
- result
14
+ def generate(options = {})
15
+ super(options) do |r|
16
+ r.template = self
17
+ end
37
18
  end
38
19
 
39
20
  def find_duplication
@@ -48,4 +29,9 @@ class Tengine::Job::RootJobnetTemplate < Tengine::Job::JobnetTemplate
48
29
  where({:name => name, :dsl_version => version}).first
49
30
  end
50
31
  end
32
+
33
+ Tengine::Job::Template::Jobnet::VERTEX_CLASSES.keys.each do |key|
34
+ instance_eval("def #{key}_class; Tengine::Job::Template::Jobnet.#{key}_class; end", __FILE__, __LINE__)
35
+ end
36
+
51
37
  end