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,167 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- require 'tengine/job/jobnet'
3
-
4
- module Tengine::Job::Jobnet::JobStateTransition
5
- include Tengine::Job::Jobnet::StateTransition
6
-
7
- # ハンドリングするドライバ: ジョブネット制御ドライバ
8
- def job_transmit(signal)
9
- self.phase_key = :ready
10
- self.started_at = signal.event.occurred_at
11
- signal.fire(self, :"start.job.job.tengine", {
12
- :target_jobnet_id => parent.id,
13
- :target_jobnet_name_path => parent.name_path,
14
- :target_job_id => self.id,
15
- :target_job_name_path => self.name_path,
16
- })
17
- end
18
- available(:job_transmit, :on => :initialized,
19
- :ignored => [:ready, :starting, :running, :dying, :success, :error, :stuck])
20
-
21
- # ハンドリングするドライバ: ジョブ制御ドライバ
22
- def job_activate(signal)
23
- case phase_key
24
- when :initialized then
25
- # 特別ルール「starting直前stop」
26
- # initializedに戻されたジョブに対して、:readyになる際にtransmitで送信されたイベントを受け取って、
27
- # activateしようとすると状態は遷移しないが、後続のエッジを実行する。
28
- # (エッジを実行しようとした際、エッジがclosedならばそのジョブネットのEndに遷移する。)
29
- next_edges.first.transmit(signal)
30
- when :ready then
31
- complete_origin_edge(signal)
32
- self.phase_key = :starting
33
- self.started_at = signal.event.occurred_at
34
- execution = signal.execution
35
- if execution.retry
36
- if execution.target_actual_ids.include?(self.id.to_s)
37
- execution.ack(signal)
38
- elsif execution.target_actuals.map{|t| t.parent.id.to_s if t.parent }.include?(self.parent.id.to_s)
39
- # 自身とTengine::Job::Execution#target_actual_idsに含まれるジョブ/ジョブネットと親が同じならば、ackしない
40
- else
41
- parent.ack(signal)
42
- end
43
- else
44
- parent.ack(signal) # 再実行でない場合
45
- end
46
- # このコールバックはjob_control_driverでupdate_with_lockの外側から
47
- # 再度呼び出してもらうためにcallbackを設定しています
48
- signal.callback = lambda{ root.vertex(self.id).activate(signal) }
49
- when :starting then
50
- # 実際にSSHでスクリプトを実行
51
- execution = signal.execution
52
- execution.signal = signal # ackを呼び返してもらうための苦肉の策
53
- begin
54
- run(execution)
55
- rescue Tengine::Job::ScriptExecutable::Error => e
56
- signal.callback = lambda do
57
- job_fail(signal, :message => e.message)
58
- end
59
- end
60
- end
61
- end
62
- available(:job_activate, :on => [:initialized, :ready, :starting],
63
- :ignored => [:running, :dying, :success, :error, :stuck])
64
-
65
- # ハンドリングするドライバ: ジョブ制御ドライバ
66
- # スクリプトのプロセスのPIDを取得できたときに実行されます
67
- def job_ack(signal)
68
- self.executing_pid = (signal.data || {})[:executing_pid]
69
- self.phase_key = :running
70
- end
71
- available(:job_ack, :on => :starting,
72
- :ignored => [:running, :dying, :success, :error, :stuck])
73
-
74
- def job_finish(signal)
75
- self.exit_status = signal.event[:exit_status]
76
- self.finished_at = signal.event.occurred_at
77
- (self.exit_status.to_s == '0') ?
78
- job_succeed(signal) :
79
- job_fail(signal)
80
- end
81
-
82
- # ハンドリングするドライバ: ジョブ制御ドライバ
83
- def job_succeed(signal)
84
- self.phase_key = :success
85
- self.finished_at = signal.event.occurred_at
86
- signal.fire(self, :"success.job.job.tengine", {
87
- :exit_status => self.exit_status,
88
- :target_jobnet_id => parent.id,
89
- :target_jobnet_name_path => parent.name_path,
90
- :target_job_id => self.id,
91
- :target_job_name_path => self.name_path,
92
- })
93
- end
94
- available :job_succeed, :on => [:starting, :running, :dying, :stuck], :ignored => [:success]
95
-
96
- # ハンドリングするドライバ: ジョブ制御ドライバ
97
- def job_fail(signal, options = nil)
98
- self.phase_key = :error
99
- if msg = signal.event[:message]
100
- self.error_messages ||= []
101
- self.error_messages += [msg]
102
- end
103
- if options && (msg = options[:message])
104
- self.error_messages ||= []
105
- self.error_messages += [msg]
106
- end
107
- self.finished_at = signal.event.occurred_at
108
- event_options = {
109
- :exit_status => self.exit_status,
110
- :target_jobnet_id => parent.id,
111
- :target_jobnet_name_path => parent.name_path,
112
- :target_job_id => self.id,
113
- :target_job_name_path => self.name_path,
114
- }
115
- event_options.update(options) if options
116
- signal.fire(self, :"error.job.job.tengine", event_options)
117
- end
118
- available :job_fail, :on => [:starting, :running, :dying], :ignored => [:error, :stuck]
119
-
120
- def job_fire_stop(signal)
121
- signal.fire(self, :"stop.job.job.tengine", {
122
- :stop_reason => signal.event[:stop_reason],
123
- :target_jobnet_id => parent.id,
124
- :target_jobnet_name_path => parent.name_path,
125
- :target_job_id => self.id,
126
- :target_job_name_path => self.name_path,
127
- })
128
- end
129
- available :job_fire_stop, :on => [:ready, :starting, :running], :ignored => [:initialized, :dying, :success, :error, :stuck]
130
-
131
- def job_stop(signal, &block)
132
- case phase_key
133
- when :ready then
134
- self.phase_key = :initialized
135
- self.stopped_at = signal.event.occurred_at
136
- self.stop_reason = signal.event[:stop_reason]
137
- next_edges.first.transmit(signal)
138
- when :starting then
139
- job = nil
140
- loop do
141
- root = self.root.reload # class.find(self.root.id)
142
- job = root.find_descendant(self.id)
143
- break unless job.phase_key == :starting
144
- yield if block_given? # テストの為にyieldしています
145
- sleep(0.1)
146
- end
147
- job.stop(signal, &block)
148
- when :running then
149
- self.phase_key = :dying
150
- self.stopped_at = signal.event.occurred_at
151
- self.stop_reason = signal.event[:stop_reason]
152
- signal.callback = lambda do
153
- kill(signal.execution)
154
- end
155
- end
156
- end
157
- available :job_stop, :on => [:ready, :starting, :running], :ignored => [:initialized, :dying, :success, :error, :stuck]
158
-
159
- def job_reset(signal, &block)
160
- self.phase_key = :initialized
161
- if signal.execution.in_scope?(self)
162
- next_edges.first.reset(signal)
163
- end
164
- end
165
- available :job_reset, :on => [:initialized, :success, :error, :stuck]
166
-
167
- end
@@ -1,110 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- require 'tengine/job/jobnet'
3
-
4
- module Tengine::Job::Jobnet::JobnetStateTransition
5
- include Tengine::Job::Jobnet::StateTransition
6
-
7
- # ハンドリングするドライバ: ジョブネット制御ドライバ or ジョブ起動ドライバ
8
- def jobnet_transmit(signal)
9
- self.phase_key = :ready
10
- signal.fire(self, :"start.jobnet.job.tengine", {
11
- :target_jobnet_id => self.id,
12
- :target_jobnet_name_path => self.name_path,
13
- })
14
- end
15
- available(:jobnet_transmit, :on => :initialized,
16
- :ignored => [:ready, :starting, :running, :dying, :success, :error, :stuck])
17
-
18
- # ハンドリングするドライバ: ジョブネット制御ドライバ
19
- def jobnet_activate(signal)
20
- self.phase_key = :starting
21
- self.started_at = signal.event.occurred_at
22
- complete_origin_edge(signal) if prev_edges && !prev_edges.empty?
23
- (parent || signal.execution).ack(signal)
24
- signal.paths << self
25
- self.start_vertex.transmit(signal)
26
- end
27
- available(:jobnet_activate, :on => :ready,
28
- :ignored => [:starting, :running, :dying, :success, :error, :stuck])
29
-
30
- # ハンドリングするドライバ: ジョブネット制御ドライバ
31
- # このackは、子要素のTengine::Job::Start#activateから呼ばれます
32
- def jobnet_ack(signal)
33
- self.phase_key = :running
34
- end
35
- available(:jobnet_ack, :on => [:initialized, :ready, :starting],
36
- :ignored => [:running, :dying, :success, :error, :stuck])
37
-
38
- # ハンドリングするドライバ: ジョブネット制御ドライバ
39
- # このackは、子要素のTengine::Job::End#activateから呼ばれます
40
- def jobnet_finish(signal)
41
- edge = end_vertex.prev_edges.first
42
- edge.closed? ?
43
- jobnet_fail(signal) :
44
- jobnet_succeed(signal)
45
- end
46
-
47
- # ハンドリングするドライバ: ジョブネット制御ドライバ
48
- def jobnet_succeed(signal)
49
- self.phase_key = :success
50
- self.finished_at = signal.event.occurred_at
51
- signal.fire(self, :"success.jobnet.job.tengine", {
52
- :target_jobnet_id => self.id,
53
- :target_jobnet_name_path => self.name_path,
54
- })
55
- end
56
- available :jobnet_succeed, :on => [:starting, :running, :dying, :stuck, :error], :ignored => [:success]
57
-
58
- # ハンドリングするドライバ: ジョブネット制御ドライバ
59
- def jobnet_fail(signal)
60
- return if self.edges.any?(&:alive?)
61
- self.phase_key = :error
62
- self.finished_at = signal.event.occurred_at
63
- signal.fire(self, :"error.jobnet.job.tengine", {
64
- :target_jobnet_id => self.id,
65
- :target_jobnet_name_path => self.name_path,
66
- })
67
- end
68
- available :jobnet_fail, :on => [:starting, :running, :dying, :success], :ignored => [:error, :stuck]
69
-
70
- def jobnet_fire_stop(signal)
71
- return if self.phase_key == :initialized
72
- signal.fire(self, :"stop.jobnet.job.tengine", {
73
- :target_jobnet_id => self.id,
74
- :target_jobnet_name_path => self.name_path,
75
- :stop_reason => signal.event[:stop_reason]
76
- })
77
- end
78
-
79
- def jobnet_stop(signal)
80
- self.phase_key = :dying
81
- self.stopped_at = signal.event.occurred_at
82
- self.stop_reason = signal.event[:stop_reason]
83
- close(signal)
84
- children.each do |child|
85
- child.fire_stop(signal) if child.respond_to?(:fire_stop)
86
- end
87
- end
88
- available :jobnet_stop, :on => [:initialized, :ready, :starting, :running], :ignored => [:dying, :success, :error, :stuck]
89
-
90
- def close(signal)
91
- self.edges.each{|edge| edge.close(signal)}
92
- end
93
-
94
-
95
- def jobnet_reset(signal, &block)
96
- # children.each{|c| c.reset(signal) }
97
- self.phase_key = :initialized
98
- if s = start_vertex
99
- s.reset(signal)
100
- end
101
- if edge = (next_edges || []).first
102
- edge.reset(signal)
103
- end
104
- rescue Exception => e
105
- puts "#{self.name_path} [#{e.class}] #{e.message}"
106
- raise
107
- end
108
- available :jobnet_reset, :on => [:initialized, :success, :error, :stuck]
109
-
110
- end
@@ -1,84 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- require 'tengine/job'
3
-
4
- # テンプレートから生成された実行時に使用されるジョブネットを表すVertex。
5
- class Tengine::Job::JobnetActual < Tengine::Job::Jobnet
6
- include Tengine::Job::ScriptExecutable
7
- include Tengine::Job::Executable
8
- include Tengine::Job::Stoppable
9
- include Tengine::Job::Jobnet::JobStateTransition
10
- include Tengine::Job::Jobnet::JobnetStateTransition
11
-
12
- field :was_expansion, :type => Boolean # テンプレートがTenigne::Job::Expansionであった場合にtrueです。
13
-
14
- # was_expansionがtrueなら元々のtemplateへの参照が必要なのでRootJobnetActualだけでなく
15
- # JobnetActualでもtemplateが必要です。
16
- belongs_to :template, :inverse_of => :root_jobnet_actuals, :index => true, :class_name => "Tengine::Job::RootJobnetTemplate"
17
-
18
- # https://cacoo.com/diagrams/hdLgrzYsTBBpV3Wj#D26C1
19
- STATE_TRANSITION_METHODS = [:transmit, :activate, :ack, :finish, :succeed, :fail, :fire_stop, :stop, :reset].freeze
20
- STATE_TRANSITION_METHODS.each do |method_name|
21
- class_eval(<<-END_OF_METHOD, __FILE__, __LINE__ + 1)
22
- def #{method_name}(signal, &block)
23
- script_executable? ?
24
- job_#{method_name}(signal, &block) :
25
- jobnet_#{method_name}(signal, &block)
26
- end
27
- END_OF_METHOD
28
- end
29
-
30
- def root_or_expansion
31
- p = parent
32
- p.nil? ? self : p.was_expansion ? p : p.root_or_expansion
33
- end
34
-
35
- # https://www.pivotaltracker.com/story/show/23329935
36
-
37
- def stop_reason= r
38
- super
39
- children.each do |i|
40
- if i.respond_to?(:chained_box?) && i.chained_box?
41
- i.stop_reason = r
42
- end
43
- end
44
- end
45
-
46
- def stopped_at= t
47
- super
48
- children.each do |i|
49
- if i.respond_to?(:chained_box?) && i.chained_box?
50
- i.stopped_at = t
51
- end
52
- end
53
- end
54
-
55
- def fire_stop_event(root_jobnet, options = Hash.new)
56
- root_jobnet_id = root_jobnet.id.to_s
57
- result = Tengine::Job::Execution.create!(
58
- options.merge(:root_jobnet_id => root_jobnet_id))
59
- properties = {
60
- :execution_id => result.id.to_s,
61
- :root_jobnet_id => root_jobnet_id,
62
- :stop_reason => "user_stop"
63
- }
64
-
65
- target_id = self.id.to_s
66
- # if target.children.blank?
67
- if script_executable?
68
- event = :"stop.job.job.tengine"
69
- properties[:target_job_id] = target_id
70
- properties[:target_jobnet_id] = parent.id.to_s
71
- else
72
- event = :"stop.jobnet.job.tengine"
73
- properties[:target_jobnet_id] = target_id
74
- end
75
-
76
- EM.run do
77
- Tengine::Event.fire(event,
78
- :source_name => name_as_resource,
79
- :properties => properties)
80
- end
81
-
82
- return result
83
- end
84
- end
@@ -1,10 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- require 'tengine/job'
3
-
4
- # ジョブDSLで定義されるジョブネットを表すVertex。
5
- class Tengine::Job::JobnetTemplate < Tengine::Job::Jobnet
6
-
7
- def actual_class
8
- Tengine::Job::JobnetActual
9
- end
10
- end
@@ -1,6 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- require 'tengine/job'
3
-
4
- # 複数のVertexの終了を待ちあわせて一つのVertexへSignalを通知する合流のVertex。
5
- class Tengine::Job::Join < Tengine::Job::Junction
6
- end
@@ -1,29 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- require 'tengine/job'
3
-
4
- # ForkやJoinの継承元となるVertex。特に状態は持たない。
5
- class Tengine::Job::Junction < Tengine::Job::Vertex
6
-
7
- # https://cacoo.com/diagrams/hdLgrzYsTBBpV3Wj#D26C1
8
- def transmit(signal)
9
- complete_origin_edge(signal, :except_closed => true)
10
- # transmitted?で判断すると、closedなものに対する処理を考慮できないので、alive?を使って判断します
11
- # activate(signal) if prev_edges.all?(&:transmitted?)
12
- execution = signal.execution
13
- predicate = execution.retry ? :alive_or_closing_or_closed? : :alive_or_closing?
14
- activate(signal) unless prev_edges.any?(&predicate)
15
- end
16
-
17
- def activatable?
18
- prev_edges.all?(&:transmitted?)
19
- end
20
-
21
- def activate(signal)
22
- signal.leave(self)
23
- end
24
-
25
- def reset(signal)
26
- signal.leave(self, :reset)
27
- end
28
-
29
- end
@@ -1,30 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- require 'tengine/job'
3
-
4
- # 終了対象となりうるVertexで使用するモジュール
5
- module Tengine::Job::Killing
6
- extend ActiveSupport::Concern
7
-
8
- included do
9
- require 'tengine/core'
10
- include Tengine::Core::CollectionAccessible
11
-
12
- field :killing_signals, :type => Array # 強制停止時にプロセスに送るシグナルの配列
13
- array_text_accessor :killing_signals
14
-
15
- field :killing_signal_interval, :type => Integer # 強制停止時にkilling_signalsで定義されるシグナルを順次送信する間隔。
16
- end
17
-
18
- DEFAULT_KILLING_SIGNAL_INTERVAL = 5
19
-
20
- def actual_killing_signals
21
- killing_signals ? killing_signals :
22
- (parent ? parent.actual_killing_signals : ['KILL'])
23
- end
24
-
25
- def actual_killing_signal_interval
26
- killing_signals ? killing_signal_interval :
27
- (parent ? parent.actual_killing_signal_interval : DEFAULT_KILLING_SIGNAL_INTERVAL)
28
- end
29
-
30
- end
@@ -1,6 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- # MM1との互換性のためのメソッドを提供するモジュール
4
- module Tengine::Job::MmCompatibility
5
- autoload :Connectable, "tengine/job/mm_compatibility/connectable"
6
- end