rukawa 0.3.2 → 0.3.3
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/README.md +15 -0
- data/lib/rukawa/abstract_job.rb +17 -11
- data/lib/rukawa/cli.rb +59 -14
- data/lib/rukawa/configuration.rb +4 -1
- data/lib/rukawa/dependency.rb +59 -0
- data/lib/rukawa/errors.rb +1 -1
- data/lib/rukawa/job.rb +56 -5
- data/lib/rukawa/overview.rb +58 -0
- data/lib/rukawa/runner.rb +4 -25
- data/lib/rukawa/state.rb +12 -0
- data/lib/rukawa/version.rb +1 -1
- data/lib/rukawa.rb +3 -1
- data/rukawa.gemspec +2 -0
- data/sample/jobs/sample_job.rb +11 -0
- data/sample/result.dot +4 -4
- data/sample/result.png +0 -0
- metadata +32 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 13b76e6a6b3bab23573723fee0d2c9049d1b5052
|
4
|
+
data.tar.gz: f39e1766871bd26e710edd2868edf39c625f1a0f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9037f65f1a2c502a52cd53b3abc2758f2dcbb9deb43595f67687325c09924a298da2a7b79505a34bed2638128a278a8c5997efe07c4c4ee1884fb8f70620e19c
|
7
|
+
data.tar.gz: 42bb250a6a17de86a9d23f2343352d26426185a176313fdef7befcd4117aa4bac846be2d93393fac3e7970d1d18b115c2dadd87936a0512cb59ace0675b91d28
|
data/README.md
CHANGED
@@ -227,6 +227,21 @@ Main usage is manual reentering.
|
|
227
227
|
% dot -Tpng -o SampleJobNet.png SampleJobNet.dot
|
228
228
|
```
|
229
229
|
|
230
|
+
### Config Example
|
231
|
+
|
232
|
+
```
|
233
|
+
# rukawa.rb
|
234
|
+
|
235
|
+
Rukawa.configure do |c|
|
236
|
+
c.logger = OtherLogger.new
|
237
|
+
c.concurrency = 4
|
238
|
+
c.graph.concentrate = true
|
239
|
+
c.graph.nodesep = 0.8
|
240
|
+
end
|
241
|
+
```
|
242
|
+
|
243
|
+
see. [Rukawa::Configuration](https://github.com/joker1007/rukawa/blob/master/lib/rukawa/configuration.rb)
|
244
|
+
|
230
245
|
### help
|
231
246
|
```
|
232
247
|
% bundle exec rukawa help run
|
data/lib/rukawa/abstract_job.rb
CHANGED
@@ -1,18 +1,28 @@
|
|
1
1
|
require 'set'
|
2
2
|
require 'rukawa/state'
|
3
|
+
require 'active_support/core_ext/class'
|
3
4
|
|
4
5
|
module Rukawa
|
5
6
|
class AbstractJob
|
6
7
|
attr_reader :parent_job_net
|
8
|
+
extend ActiveSupport::DescendantsTracker
|
7
9
|
|
10
|
+
class_attribute :skip_rules, instance_writer: false
|
11
|
+
self.skip_rules = []
|
8
12
|
class << self
|
9
|
-
def
|
10
|
-
|
13
|
+
def add_skip_rule(callable_or_symbol)
|
14
|
+
self.skip_rules = skip_rules + [callable_or_symbol]
|
11
15
|
end
|
12
16
|
|
13
|
-
def
|
14
|
-
|
17
|
+
def description
|
18
|
+
@description
|
19
|
+
end
|
20
|
+
alias :desc :description
|
21
|
+
|
22
|
+
def set_description(body)
|
23
|
+
@description = body
|
15
24
|
end
|
25
|
+
alias :set_desc :set_description
|
16
26
|
end
|
17
27
|
|
18
28
|
def name
|
@@ -30,10 +40,6 @@ module Rukawa
|
|
30
40
|
end
|
31
41
|
end
|
32
42
|
|
33
|
-
def skip_rules
|
34
|
-
self.class.skip_rules
|
35
|
-
end
|
36
|
-
|
37
43
|
def elapsed_time_from(time = Time.now)
|
38
44
|
return finished_at - started_at if started_at && finished_at
|
39
45
|
return time - started_at if started_at
|
@@ -46,11 +52,11 @@ module Rukawa
|
|
46
52
|
return "N/A" unless elapsed
|
47
53
|
|
48
54
|
hour = elapsed.to_i / 3600
|
49
|
-
min = elapsed.to_i / 60
|
55
|
+
min = (elapsed - hour * 3600).to_i / 60
|
50
56
|
sec = (elapsed - hour * 3600 - min * 60).to_i
|
51
57
|
|
52
|
-
hour_format =
|
53
|
-
min_format = min > 0 ? "%dm " % min : ""
|
58
|
+
hour_format = hour > 0 ? "%dh " % hour : ""
|
59
|
+
min_format = hour > 0 || min > 0 ? "%dm " % min : ""
|
54
60
|
sec_format = "#{sec}s"
|
55
61
|
"#{hour_format}#{min_format}#{sec_format}"
|
56
62
|
end
|
data/lib/rukawa/cli.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'thor'
|
2
2
|
require 'rukawa/runner'
|
3
|
+
require 'rukawa/overview'
|
3
4
|
|
4
5
|
module Rukawa
|
5
6
|
class Cli < Thor
|
@@ -10,20 +11,19 @@ module Rukawa
|
|
10
11
|
method_option :config, type: :string, default: nil, desc: "If this options is not set, try to load ./rukawa.rb"
|
11
12
|
method_option :job_dirs, type: :array, default: [], desc: "Load job directories"
|
12
13
|
method_option :batch, aliases: "-b", type: :boolean, default: false, desc: "If batch mode, not display running status"
|
13
|
-
method_option :log, aliases: "-l", type: :string,
|
14
|
+
method_option :log, aliases: "-l", type: :string, desc: "Default: ./rukawa.log"
|
14
15
|
method_option :stdout, type: :boolean, default: false, desc: "Output log to stdout"
|
16
|
+
method_option :syslog, type: :boolean, default: false, desc: "Output log to syslog"
|
15
17
|
method_option :dot, aliases: "-d", type: :string, default: nil, desc: "Output job status by dot format"
|
16
18
|
method_option :refresh_interval, aliases: "-r", type: :numeric, default: 3, desc: "Refresh interval for running status information"
|
17
19
|
def _run(job_net_name, *job_name)
|
18
20
|
load_config
|
19
|
-
|
20
|
-
|
21
|
-
c.concurrency = options[:concurrency] if options[:concurrency]
|
22
|
-
end
|
21
|
+
set_logger
|
22
|
+
set_concurrency
|
23
23
|
load_job_definitions
|
24
24
|
|
25
|
-
job_net_class =
|
26
|
-
job_classes = job_name.map { |name|
|
25
|
+
job_net_class = get_class(job_net_name)
|
26
|
+
job_classes = job_name.map { |name| get_class(name) }
|
27
27
|
job_net = job_net_class.new(nil, *job_classes)
|
28
28
|
result = Runner.run(job_net, options[:batch], options[:refresh_interval])
|
29
29
|
|
@@ -42,8 +42,8 @@ module Rukawa
|
|
42
42
|
load_config
|
43
43
|
load_job_definitions
|
44
44
|
|
45
|
-
job_net_class =
|
46
|
-
job_classes = job_name.map { |name|
|
45
|
+
job_net_class = get_class(job_net_name)
|
46
|
+
job_classes = job_name.map { |name| get_class(name) }
|
47
47
|
job_net = job_net_class.new(nil, *job_classes)
|
48
48
|
job_net.output_dot(options[:output])
|
49
49
|
end
|
@@ -60,13 +60,11 @@ module Rukawa
|
|
60
60
|
method_option :refresh_interval, aliases: "-r", type: :numeric, default: 3, desc: "Refresh interval for running status information"
|
61
61
|
def run_job(*job_name)
|
62
62
|
load_config
|
63
|
-
|
64
|
-
|
65
|
-
c.concurrency = options[:concurrency] if options[:concurrency]
|
66
|
-
end
|
63
|
+
set_logger
|
64
|
+
set_concurrency
|
67
65
|
load_job_definitions
|
68
66
|
|
69
|
-
job_classes = job_name.map { |name|
|
67
|
+
job_classes = job_name.map { |name| get_class(name) }
|
70
68
|
job_net_class = anonymous_job_net_class(*job_classes)
|
71
69
|
job_net = job_net_class.new(nil)
|
72
70
|
result = Runner.run(job_net, options[:batch], options[:refresh_interval])
|
@@ -78,6 +76,25 @@ module Rukawa
|
|
78
76
|
exit 1 unless result
|
79
77
|
end
|
80
78
|
|
79
|
+
desc "list", "List JobNet"
|
80
|
+
method_option :config, type: :string, default: nil, desc: "If this options is not set, try to load ./rukawa.rb"
|
81
|
+
method_option :jobs, aliases: "-j", type: :boolean, desc: "Show jobs", default: false
|
82
|
+
method_option :job_dirs, type: :array, default: [], desc: "Load job directories"
|
83
|
+
def list
|
84
|
+
load_config
|
85
|
+
load_job_definitions
|
86
|
+
Rukawa::Overview.list_job_net(with_jobs: options[:jobs])
|
87
|
+
end
|
88
|
+
|
89
|
+
desc "list_job", "List Job"
|
90
|
+
method_option :config, type: :string, default: nil, desc: "If this options is not set, try to load ./rukawa.rb"
|
91
|
+
method_option :job_dirs, type: :array, default: [], desc: "Load job directories"
|
92
|
+
def list_job
|
93
|
+
load_config
|
94
|
+
load_job_definitions
|
95
|
+
Rukawa::Overview.list_job
|
96
|
+
end
|
97
|
+
|
81
98
|
private
|
82
99
|
|
83
100
|
def load_config
|
@@ -88,6 +105,27 @@ module Rukawa
|
|
88
105
|
end
|
89
106
|
end
|
90
107
|
|
108
|
+
def set_logger
|
109
|
+
Rukawa.configure do |c|
|
110
|
+
if options[:stdout]
|
111
|
+
c.logger = Logger.new($stdout)
|
112
|
+
elsif options[:syslog]
|
113
|
+
require 'syslog/logger'
|
114
|
+
c.logger = Syslog::Logger.new('rukawa')
|
115
|
+
elsif options[:log]
|
116
|
+
c.logger = Logger.new(options[:log])
|
117
|
+
else
|
118
|
+
c.logger ||= Logger.new('./rukawa.log');
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def set_concurrency
|
124
|
+
Rukawa.configure do |c|
|
125
|
+
c.concurrency = options[:concurrency] if options[:concurrency]
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
91
129
|
def default_config_file
|
92
130
|
"./rukawa.rb"
|
93
131
|
end
|
@@ -103,6 +141,13 @@ module Rukawa
|
|
103
141
|
end
|
104
142
|
end
|
105
143
|
|
144
|
+
def get_class(name)
|
145
|
+
Object.const_get(name)
|
146
|
+
rescue NameError
|
147
|
+
$stderr.puts("`#{name}` class is not found")
|
148
|
+
exit 1
|
149
|
+
end
|
150
|
+
|
106
151
|
def anonymous_job_net_class(*job_classes)
|
107
152
|
Class.new(JobNet) do
|
108
153
|
self.singleton_class.send(:define_method, :dependencies) do
|
data/lib/rukawa/configuration.rb
CHANGED
@@ -6,9 +6,12 @@ require 'concurrent'
|
|
6
6
|
module Rukawa
|
7
7
|
class Configuration < Delegator
|
8
8
|
include Singleton
|
9
|
+
attr_accessor :logger
|
9
10
|
|
10
11
|
def initialize
|
11
|
-
@config = OpenStruct.new(
|
12
|
+
@config = OpenStruct.new(
|
13
|
+
concurrency: Concurrent.processor_count
|
14
|
+
)
|
12
15
|
@config.graph = GraphConfig.new.tap { |c| c.rankdir = "LR" }
|
13
16
|
end
|
14
17
|
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Rukawa
|
2
|
+
module Dependency
|
3
|
+
def self.get(name)
|
4
|
+
const_get(name.to_s.split("_").map(&:capitalize).join)
|
5
|
+
end
|
6
|
+
|
7
|
+
class Base
|
8
|
+
def initialize(*results)
|
9
|
+
@results = results
|
10
|
+
end
|
11
|
+
|
12
|
+
def resolve
|
13
|
+
raise NotImplementedError
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class AllSuccess < Base
|
18
|
+
def resolve
|
19
|
+
@results.all? { |r| r && r.success? }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class AllDone < Base
|
24
|
+
def resolve
|
25
|
+
true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class OneSuccess < Base
|
30
|
+
def resolve
|
31
|
+
@results.empty? || @results.any? { |r| r && r.success? }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class AllSuccessOrSkipped < Base
|
36
|
+
def resolve
|
37
|
+
@results.all? { |r| r && (r.success? || r.skipped?) }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class OneSuccessOrSkipped < Base
|
42
|
+
def resolve
|
43
|
+
@results.empty? || @results.any? { |r| r && (r.success? || r.skipped?) }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class AllFailed < Base
|
48
|
+
def resolve
|
49
|
+
@results.none? { |r| r }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class OneFailed < Base
|
54
|
+
def resolve
|
55
|
+
@results.empty? || @results.any? { |r| r.nil? }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/rukawa/errors.rb
CHANGED
data/lib/rukawa/job.rb
CHANGED
@@ -1,15 +1,37 @@
|
|
1
1
|
require 'concurrent'
|
2
2
|
require 'rukawa/abstract_job'
|
3
|
+
require 'rukawa/dependency'
|
4
|
+
require 'rukawa/state'
|
5
|
+
require 'active_support/core_ext/class'
|
3
6
|
|
4
7
|
module Rukawa
|
5
8
|
class Job < AbstractJob
|
6
9
|
attr_accessor :in_comings, :out_goings
|
7
10
|
attr_reader :state, :started_at, :finished_at
|
8
11
|
|
12
|
+
class_attribute :retryable, :retry_limit, :retry_exception_type, :retry_wait, instance_writer: false
|
13
|
+
class_attribute :dependency_type, instance_writer: false
|
14
|
+
self.dependency_type = Dependency::AllSuccess
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def set_retryable(limit: 8, type: nil, wait: nil)
|
18
|
+
self.retryable = true
|
19
|
+
self.retry_limit = limit
|
20
|
+
self.retry_exception_type = type
|
21
|
+
self.retry_wait = wait
|
22
|
+
end
|
23
|
+
|
24
|
+
def set_dependency_type(name)
|
25
|
+
self.dependency_type = Rukawa::Dependency.get(name)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
9
29
|
def initialize(parent_job_net)
|
10
30
|
@parent_job_net = parent_job_net
|
11
31
|
@in_comings = Set.new
|
12
32
|
@out_goings = Set.new
|
33
|
+
@retry_count = 0
|
34
|
+
@retry_wait = 1
|
13
35
|
set_state(:waiting)
|
14
36
|
end
|
15
37
|
|
@@ -42,7 +64,7 @@ module Rukawa
|
|
42
64
|
@started_at = Time.now
|
43
65
|
check_dependencies(results)
|
44
66
|
|
45
|
-
if skip?
|
67
|
+
if skip?
|
46
68
|
Rukawa.logger.info("Skip #{self.class}")
|
47
69
|
set_state(:skipped)
|
48
70
|
else
|
@@ -54,7 +76,8 @@ module Rukawa
|
|
54
76
|
end
|
55
77
|
rescue => e
|
56
78
|
handle_error(e)
|
57
|
-
|
79
|
+
Rukawa.logger.error("Retry #{self.class}")
|
80
|
+
retry
|
58
81
|
ensure
|
59
82
|
@finished_at = Time.now
|
60
83
|
end
|
@@ -85,16 +108,44 @@ module Rukawa
|
|
85
108
|
end
|
86
109
|
end
|
87
110
|
|
111
|
+
def dependency_type
|
112
|
+
self.class.dependency_type
|
113
|
+
end
|
114
|
+
|
88
115
|
def check_dependencies(results)
|
89
|
-
|
116
|
+
dependency = dependency_type.new(*results)
|
117
|
+
unless dependency.resolve
|
90
118
|
set_state(:aborted)
|
91
|
-
raise
|
119
|
+
raise DependencyUnsatisfied
|
92
120
|
end
|
93
121
|
end
|
94
122
|
|
95
123
|
def handle_error(e)
|
96
124
|
Rukawa.logger.error("Error #{self.class} by #{e}")
|
97
|
-
|
125
|
+
if retry?(e)
|
126
|
+
@retry_count += 1
|
127
|
+
set_state(:waiting)
|
128
|
+
sleep @retry_wait
|
129
|
+
@retry_wait = self.class.retry_wait ? self.class.retry_wait : @retry_wait * 2
|
130
|
+
else
|
131
|
+
set_state(:error) unless e.is_a?(DependencyUnsatisfied)
|
132
|
+
raise e
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def retry?(e)
|
137
|
+
return false unless self.class.retryable
|
138
|
+
|
139
|
+
type_condition = case self.class.retry_exception_type
|
140
|
+
when Array
|
141
|
+
self.class.retry_exception_type.include?(e.class)
|
142
|
+
when Class
|
143
|
+
e.is_a?(self.class.retry_exception_type)
|
144
|
+
when nil
|
145
|
+
!e.is_a?(DependencyUnsatisfied)
|
146
|
+
end
|
147
|
+
|
148
|
+
type_condition && (self.class.retry_limit.nil? || self.class.retry_limit == 0 || @retry_count < self.class.retry_limit)
|
98
149
|
end
|
99
150
|
|
100
151
|
def store(key, value)
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Rukawa
|
2
|
+
module Overview
|
3
|
+
class << self
|
4
|
+
def list_job_net(with_jobs: false)
|
5
|
+
header = ["Job", "Desc"]
|
6
|
+
header << "Dependencies" if with_jobs
|
7
|
+
table = Terminal::Table.new headings: header do |t|
|
8
|
+
JobNet.descendants.each do |job_net|
|
9
|
+
list_table_row(t, job_net, job_net.dependencies, with_jobs: with_jobs)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
puts table
|
13
|
+
end
|
14
|
+
|
15
|
+
def list_job
|
16
|
+
header = ["Job", "Desc"]
|
17
|
+
table = Terminal::Table.new headings: header do |t|
|
18
|
+
Job.descendants.each do |job|
|
19
|
+
row = [Paint[job.name, :bold, :underline], job.desc]
|
20
|
+
t << row
|
21
|
+
end
|
22
|
+
end
|
23
|
+
puts table
|
24
|
+
end
|
25
|
+
|
26
|
+
def list_table_row(table, job_net, level = 0, with_jobs: false)
|
27
|
+
row = [Paint[job_net.name, :bold, :underline], job_net.desc]
|
28
|
+
row << "" if with_jobs
|
29
|
+
table << row
|
30
|
+
if with_jobs
|
31
|
+
job_net.dependencies.each do |inner_j, deps|
|
32
|
+
table << [Paint["#{" "}#{inner_j.name}"], inner_j.desc, deps.join(", ")]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def display_running_status(root_job_net)
|
38
|
+
table = Terminal::Table.new headings: ["Job", "Status", "Elapsed Time"] do |t|
|
39
|
+
root_job_net.each_with_index do |j|
|
40
|
+
running_table_row(t, j)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
puts table
|
44
|
+
end
|
45
|
+
|
46
|
+
def running_table_row(table, job, level = 0)
|
47
|
+
if job.is_a?(JobNet)
|
48
|
+
table << [Paint["#{" " * level}#{job.class}", :bold, :underline], Paint[job.state.colored, :bold, :underline], Paint[job.formatted_elapsed_time_from, :bold, :underline]]
|
49
|
+
job.each do |inner_j|
|
50
|
+
running_table_row(table, inner_j, level + 1)
|
51
|
+
end
|
52
|
+
else
|
53
|
+
table << [Paint["#{" " * level}#{job.class}", :bold], job.state.colored, job.formatted_elapsed_time_from]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/rukawa/runner.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'terminal-table'
|
2
2
|
require 'paint'
|
3
|
+
require 'rukawa/overview'
|
3
4
|
|
4
5
|
module Rukawa
|
5
6
|
class Runner
|
@@ -18,19 +19,19 @@ module Rukawa
|
|
18
19
|
Rukawa.logger.info("=== Start Rukawa ===")
|
19
20
|
futures = @root_job_net.dataflows.each(&:execute)
|
20
21
|
until futures.all?(&:complete?)
|
21
|
-
|
22
|
+
Overview.display_running_status(@root_job_net) unless batch_mode
|
22
23
|
sleep refresh_interval
|
23
24
|
end
|
24
25
|
Rukawa.logger.info("=== Finish Rukawa ===")
|
25
26
|
|
26
|
-
|
27
|
+
Overview.display_running_status(@root_job_net) unless batch_mode
|
27
28
|
puts "Finished #{@root_job_net.name} in #{@root_job_net.formatted_elapsed_time_from}"
|
28
29
|
|
29
30
|
errors = futures.map(&:reason).compact
|
30
31
|
|
31
32
|
unless errors.empty?
|
32
33
|
errors.each do |err|
|
33
|
-
next if err.is_a?(
|
34
|
+
next if err.is_a?(DependencyUnsatisfied)
|
34
35
|
Rukawa.logger.error(err)
|
35
36
|
end
|
36
37
|
return false
|
@@ -38,27 +39,5 @@ module Rukawa
|
|
38
39
|
|
39
40
|
true
|
40
41
|
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def display_table
|
45
|
-
table = Terminal::Table.new headings: ["Job", "Status", "Elapsed Time"] do |t|
|
46
|
-
@root_job_net.each_with_index do |j|
|
47
|
-
table_row(t, j)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
puts table
|
51
|
-
end
|
52
|
-
|
53
|
-
def table_row(table, job, level = 0)
|
54
|
-
if job.is_a?(JobNet)
|
55
|
-
table << [Paint["#{" " * level}#{job.class}", :bold, :underline], Paint[job.state.colored, :bold, :underline], Paint[job.formatted_elapsed_time_from, :bold, :underline]]
|
56
|
-
job.each do |inner_j|
|
57
|
-
table_row(table, inner_j, level + 1)
|
58
|
-
end
|
59
|
-
else
|
60
|
-
table << [Paint["#{" " * level}#{job.class}", :bold], job.state.colored, job.formatted_elapsed_time_from]
|
61
|
-
end
|
62
|
-
end
|
63
42
|
end
|
64
43
|
end
|
data/lib/rukawa/state.rb
CHANGED
@@ -16,6 +16,10 @@ module Rukawa::State
|
|
16
16
|
other
|
17
17
|
end
|
18
18
|
|
19
|
+
def success?
|
20
|
+
false
|
21
|
+
end
|
22
|
+
|
19
23
|
%i(running? skipped? bypassed? error? aborted? waiting? finished?).each do |sym|
|
20
24
|
define_method(sym) do
|
21
25
|
false
|
@@ -66,6 +70,10 @@ module Rukawa::State
|
|
66
70
|
:yellow
|
67
71
|
end
|
68
72
|
|
73
|
+
def self.success?
|
74
|
+
true
|
75
|
+
end
|
76
|
+
|
69
77
|
def self.bypassed?
|
70
78
|
true
|
71
79
|
end
|
@@ -138,6 +146,10 @@ module Rukawa::State
|
|
138
146
|
:green
|
139
147
|
end
|
140
148
|
|
149
|
+
def self.success?
|
150
|
+
true
|
151
|
+
end
|
152
|
+
|
141
153
|
def self.finished?
|
142
154
|
true
|
143
155
|
end
|
data/lib/rukawa/version.rb
CHANGED
data/lib/rukawa.rb
CHANGED
@@ -3,7 +3,7 @@ require "concurrent"
|
|
3
3
|
module Rukawa
|
4
4
|
class << self
|
5
5
|
def logger
|
6
|
-
|
6
|
+
config.logger
|
7
7
|
end
|
8
8
|
|
9
9
|
def store
|
@@ -24,9 +24,11 @@ module Rukawa
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
require 'active_support'
|
27
28
|
require "rukawa/version"
|
28
29
|
require 'rukawa/errors'
|
29
30
|
require 'rukawa/state'
|
31
|
+
require 'rukawa/dependency'
|
30
32
|
require 'rukawa/configuration'
|
31
33
|
require 'rukawa/job_net'
|
32
34
|
require 'rukawa/job'
|
data/rukawa.gemspec
CHANGED
@@ -18,6 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
+
spec.add_runtime_dependency "activesupport", ">= 4"
|
21
22
|
spec.add_runtime_dependency "concurrent-ruby"
|
22
23
|
spec.add_runtime_dependency "thor"
|
23
24
|
spec.add_runtime_dependency "terminal-table"
|
@@ -27,4 +28,5 @@ Gem::Specification.new do |spec|
|
|
27
28
|
spec.add_development_dependency "rake", "~> 10.0"
|
28
29
|
spec.add_development_dependency "rspec", "~> 3.0"
|
29
30
|
spec.add_development_dependency "rspec-power_assert"
|
31
|
+
spec.add_development_dependency "rspec-parameterized"
|
30
32
|
end
|
data/sample/jobs/sample_job.rb
CHANGED
@@ -12,19 +12,29 @@ class SampleJob < Rukawa::Job
|
|
12
12
|
end
|
13
13
|
|
14
14
|
class Job1 < SampleJob
|
15
|
+
set_description "Job1 description body"
|
15
16
|
end
|
16
17
|
class Job2 < SampleJob
|
18
|
+
def run
|
19
|
+
raise "job2 error"
|
20
|
+
end
|
17
21
|
end
|
18
22
|
class Job3 < SampleJob
|
19
23
|
end
|
20
24
|
class Job4 < SampleJob
|
25
|
+
# inherited by subclass
|
26
|
+
set_dependency_type :one_success
|
21
27
|
end
|
22
28
|
class Job5 < SampleJob
|
29
|
+
# inherited by subclass
|
30
|
+
set_retryable limit: 3, wait: 2, type: RuntimeError
|
31
|
+
|
23
32
|
def run
|
24
33
|
raise "job5 error"
|
25
34
|
end
|
26
35
|
end
|
27
36
|
class Job6 < SampleJob
|
37
|
+
set_dependency_type :one_failed
|
28
38
|
end
|
29
39
|
class Job7 < SampleJob
|
30
40
|
end
|
@@ -47,6 +57,7 @@ class InnerJob4 < SampleJob
|
|
47
57
|
end
|
48
58
|
|
49
59
|
class InnerJob5 < SampleJob
|
60
|
+
# inherited by subclass
|
50
61
|
add_skip_rule ->(job) { job.is_a?(SampleJob) }
|
51
62
|
end
|
52
63
|
|
data/sample/result.dot
CHANGED
@@ -2,7 +2,7 @@ digraph "SampleJobNet" {
|
|
2
2
|
label = "SampleJobNet";
|
3
3
|
graph [rankdir = LR,nodesep = 0.8,concentrate = true];
|
4
4
|
Job1 [style = filled,fillcolor = green];
|
5
|
-
Job2 [style = filled,fillcolor =
|
5
|
+
Job2 [style = filled,fillcolor = red];
|
6
6
|
Job3 [style = filled,fillcolor = green];
|
7
7
|
Job4 [style = filled,fillcolor = green];
|
8
8
|
subgraph "cluster_InnerJobNet" {
|
@@ -17,15 +17,15 @@ InnerJob2 [style = filled,fillcolor = red];
|
|
17
17
|
}
|
18
18
|
Job8 [style = filled,fillcolor = magenta];
|
19
19
|
Job5 [style = filled,fillcolor = red];
|
20
|
-
Job6 [style = filled,fillcolor =
|
21
|
-
Job7 [style = filled,fillcolor =
|
20
|
+
Job6 [style = filled,fillcolor = green];
|
21
|
+
Job7 [style = filled,fillcolor = green];
|
22
22
|
subgraph "cluster_InnerJobNet2" {
|
23
23
|
label = "InnerJobNet2";
|
24
24
|
graph [rankdir = LR,nodesep = 0.8,concentrate = true];
|
25
25
|
color = blue;
|
26
26
|
InnerJob4 [style = filled,fillcolor = green];
|
27
27
|
InnerJob5 [style = filled,fillcolor = yellow];
|
28
|
-
InnerJob6 [style = filled,fillcolor =
|
28
|
+
InnerJob6 [style = filled,fillcolor = magenta];
|
29
29
|
"InnerJob4" -> "InnerJob5";
|
30
30
|
"InnerJob4" -> "InnerJob6";
|
31
31
|
"InnerJob5" -> "InnerJob6";
|
data/sample/result.png
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rukawa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- joker1007
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-04-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: concurrent-ruby
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -122,6 +136,20 @@ dependencies:
|
|
122
136
|
- - ">="
|
123
137
|
- !ruby/object:Gem::Version
|
124
138
|
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rspec-parameterized
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
125
153
|
description: Hyper simple job workflow engine
|
126
154
|
email:
|
127
155
|
- kakyoin.hierophant@gmail.com
|
@@ -144,9 +172,11 @@ files:
|
|
144
172
|
- lib/rukawa/cli.rb
|
145
173
|
- lib/rukawa/configuration.rb
|
146
174
|
- lib/rukawa/dag.rb
|
175
|
+
- lib/rukawa/dependency.rb
|
147
176
|
- lib/rukawa/errors.rb
|
148
177
|
- lib/rukawa/job.rb
|
149
178
|
- lib/rukawa/job_net.rb
|
179
|
+
- lib/rukawa/overview.rb
|
150
180
|
- lib/rukawa/runner.rb
|
151
181
|
- lib/rukawa/state.rb
|
152
182
|
- lib/rukawa/version.rb
|