rukawa 0.5.1 → 0.6.0
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 +17 -1
- data/lib/rukawa.rb +1 -10
- data/lib/rukawa/cli.rb +9 -4
- data/lib/rukawa/context.rb +16 -0
- data/lib/rukawa/dag.rb +2 -2
- data/lib/rukawa/job.rb +8 -7
- data/lib/rukawa/job_net.rb +29 -3
- data/lib/rukawa/overview.rb +2 -2
- data/lib/rukawa/runner.rb +13 -18
- data/lib/rukawa/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 34dae79e6a5490afb50c25cd0f1a6784bba6e0da
|
4
|
+
data.tar.gz: 3e0df7f16eceb68d984fb0219fa5c7349fb529be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aa945187329bc472dc19f63e9086eba30232711100763e461f025cb44f6941755a5036a1fcac7872b414ff427f73ae3887daef221225fb617dca1fafc25650fc
|
7
|
+
data.tar.gz: 5a03f462462c210c33f03ec2bc61acf45c386c4c25314539f4d42af05b7e48aaf870782142df15281a6eb59fc8f4bd3d887e31211927239323e4c1c3bef11f6e
|
data/README.md
CHANGED
@@ -385,9 +385,25 @@ Options:
|
|
385
385
|
Output jobnet graph. If JOB_NET is set, simulate resumed job sequence
|
386
386
|
```
|
387
387
|
|
388
|
+
### Usage from Ruby program
|
389
|
+
|
390
|
+
```ruby
|
391
|
+
currency = 4
|
392
|
+
job_net = YourJobNetClass.new(nil, {"var1" => "value1"}, Context.new(currency))
|
393
|
+
promise = job_net.run do
|
394
|
+
puts "Job Running"
|
395
|
+
end
|
396
|
+
|
397
|
+
promise.then do |futures|
|
398
|
+
errors = futures.map(&:reason).compact
|
399
|
+
unless errors.empty?
|
400
|
+
puts "JobNet has errors"
|
401
|
+
end
|
402
|
+
end
|
403
|
+
```
|
404
|
+
|
388
405
|
## ToDo
|
389
406
|
- Write more tests
|
390
|
-
- Enable use variables
|
391
407
|
|
392
408
|
## Development
|
393
409
|
|
data/lib/rukawa.rb
CHANGED
@@ -2,16 +2,6 @@ require "concurrent"
|
|
2
2
|
|
3
3
|
module Rukawa
|
4
4
|
class << self
|
5
|
-
def init
|
6
|
-
unless @initialized
|
7
|
-
@store = Concurrent::Hash.new
|
8
|
-
@executor = Concurrent::FixedThreadPool.new(config.concurrency)
|
9
|
-
@semaphore = Concurrent::Semaphore.new(config.concurrency)
|
10
|
-
@initialized = true
|
11
|
-
end
|
12
|
-
end
|
13
|
-
attr_reader :store, :executor, :semaphore
|
14
|
-
|
15
5
|
def logger
|
16
6
|
config.logger
|
17
7
|
end
|
@@ -35,6 +25,7 @@ end
|
|
35
25
|
|
36
26
|
require 'active_support'
|
37
27
|
require "rukawa/version"
|
28
|
+
require 'rukawa/context'
|
38
29
|
require 'rukawa/errors'
|
39
30
|
require 'rukawa/state'
|
40
31
|
require 'rukawa/dependency'
|
data/lib/rukawa/cli.rb
CHANGED
@@ -35,14 +35,19 @@ module Rukawa
|
|
35
35
|
|
36
36
|
job_net_class = get_class(job_net_name)
|
37
37
|
job_classes = job_name.map { |name| get_class(name) }
|
38
|
-
job_net = job_net_class.new(nil, variables, *job_classes)
|
38
|
+
job_net = job_net_class.new(nil, variables, Context.new, *job_classes)
|
39
39
|
result = Runner.run(job_net, options[:batch], options[:refresh_interval])
|
40
40
|
|
41
41
|
if options[:dot]
|
42
42
|
job_net.output_dot(options[:dot], format: options[:format])
|
43
43
|
end
|
44
44
|
|
45
|
-
|
45
|
+
unless result
|
46
|
+
puts "\nIf you want to retry, run following command."
|
47
|
+
failed_jobs = job_net.dag.jobs.each_with_object([]) { |j, arr| arr << j.class.to_s if j.state == Rukawa::State::Error }
|
48
|
+
puts " rukawa run #{job_net_name} #{failed_jobs.join(" ")}"
|
49
|
+
exit 1
|
50
|
+
end
|
46
51
|
end
|
47
52
|
|
48
53
|
desc "graph JOB_NET_NAME [JOB_NAME] [JOB_NAME] ...", "Output jobnet graph. If JOB_NET is set, simulate resumed job sequence"
|
@@ -55,7 +60,7 @@ module Rukawa
|
|
55
60
|
|
56
61
|
job_net_class = get_class(job_net_name)
|
57
62
|
job_classes = job_name.map { |name| get_class(name) }
|
58
|
-
job_net = job_net_class.new(nil, {}, *job_classes)
|
63
|
+
job_net = job_net_class.new(nil, {}, Context.new, *job_classes)
|
59
64
|
job_net.output_dot(options[:output], format: options[:format])
|
60
65
|
end
|
61
66
|
|
@@ -70,7 +75,7 @@ module Rukawa
|
|
70
75
|
|
71
76
|
job_classes = job_name.map { |name| get_class(name) }
|
72
77
|
job_net_class = anonymous_job_net_class(*job_classes)
|
73
|
-
job_net = job_net_class.new(nil, variables)
|
78
|
+
job_net = job_net_class.new(nil, variables, Context.new)
|
74
79
|
result = Runner.run(job_net, options[:batch], options[:refresh_interval])
|
75
80
|
|
76
81
|
if options[:dot]
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Rukawa
|
2
|
+
class Context
|
3
|
+
attr_reader :store, :executor, :semaphore
|
4
|
+
|
5
|
+
def initialize(currency = nil)
|
6
|
+
@store = Concurrent::Hash.new
|
7
|
+
@executor = Concurrent::FixedThreadPool.new(currency || Rukawa.config.concurrency)
|
8
|
+
@executor.auto_terminate = true
|
9
|
+
@semaphore = Concurrent::Semaphore.new(currency || Rukawa.config.concurrency)
|
10
|
+
end
|
11
|
+
|
12
|
+
def shutdown
|
13
|
+
@executor.shutdown if @executor.running?
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/rukawa/dag.rb
CHANGED
@@ -14,11 +14,11 @@ module Rukawa
|
|
14
14
|
@edges = Set.new
|
15
15
|
end
|
16
16
|
|
17
|
-
def build(job_net, variables, dependencies)
|
17
|
+
def build(job_net, variables, context, dependencies)
|
18
18
|
deps = tsortable_hash(dependencies).tsort
|
19
19
|
|
20
20
|
deps.each do |job_class|
|
21
|
-
job = job_class.new(job_net, variables)
|
21
|
+
job = job_class.new(job_net, variables, context)
|
22
22
|
@nodes << job
|
23
23
|
@jobs << job if job.is_a?(Job)
|
24
24
|
|
data/lib/rukawa/job.rb
CHANGED
@@ -86,9 +86,10 @@ module Rukawa
|
|
86
86
|
set_state(:finished)
|
87
87
|
end
|
88
88
|
|
89
|
-
def initialize(parent_job_net, variables)
|
89
|
+
def initialize(parent_job_net, variables, context)
|
90
90
|
@parent_job_net = parent_job_net
|
91
91
|
@variables = variables
|
92
|
+
@context = context
|
92
93
|
@in_comings = Set.new
|
93
94
|
@out_goings = Set.new
|
94
95
|
@retry_count = 0
|
@@ -112,7 +113,7 @@ module Rukawa
|
|
112
113
|
return @dataflow if @dataflow
|
113
114
|
return @dataflow = bypass_dataflow if @state.bypassed?
|
114
115
|
|
115
|
-
@dataflow = Concurrent.dataflow_with(
|
116
|
+
@dataflow = Concurrent.dataflow_with(@context.executor, *depend_dataflows) do |*results|
|
116
117
|
do_run(*results)
|
117
118
|
@state
|
118
119
|
end
|
@@ -162,7 +163,7 @@ module Rukawa
|
|
162
163
|
end
|
163
164
|
|
164
165
|
def bypass_dataflow
|
165
|
-
Concurrent.dataflow_with(
|
166
|
+
Concurrent.dataflow_with(@context.executor, *depend_dataflows) do
|
166
167
|
Rukawa.logger.info("Skip #{self.class}")
|
167
168
|
@state
|
168
169
|
end
|
@@ -209,8 +210,8 @@ module Rukawa
|
|
209
210
|
end
|
210
211
|
|
211
212
|
def store(key, value)
|
212
|
-
|
213
|
-
|
213
|
+
@context.store[self.class] ||= Concurrent::Hash.new
|
214
|
+
@context.store[self.class][key] = value
|
214
215
|
end
|
215
216
|
|
216
217
|
def resource_count
|
@@ -218,10 +219,10 @@ module Rukawa
|
|
218
219
|
end
|
219
220
|
|
220
221
|
def acquire_resource
|
221
|
-
|
222
|
+
@context.semaphore.acquire(resource_count)
|
222
223
|
yield
|
223
224
|
ensure
|
224
|
-
|
225
|
+
@context.semaphore.release(resource_count)
|
225
226
|
end
|
226
227
|
end
|
227
228
|
end
|
data/lib/rukawa/job_net.rb
CHANGED
@@ -3,7 +3,7 @@ require 'rukawa/abstract_job'
|
|
3
3
|
module Rukawa
|
4
4
|
class JobNet < AbstractJob
|
5
5
|
include Enumerable
|
6
|
-
attr_reader :dag
|
6
|
+
attr_reader :dag, :context
|
7
7
|
|
8
8
|
class << self
|
9
9
|
def dependencies
|
@@ -11,10 +11,11 @@ module Rukawa
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
def initialize(parent_job_net, variables, *resume_job_classes)
|
14
|
+
def initialize(parent_job_net, variables, context, *resume_job_classes)
|
15
15
|
@parent_job_net = parent_job_net
|
16
|
+
@context = context
|
16
17
|
@dag = Dag.new
|
17
|
-
@dag.build(self, variables, self.class.dependencies)
|
18
|
+
@dag.build(self, variables, context, self.class.dependencies)
|
18
19
|
@resume_job_classes = resume_job_classes
|
19
20
|
|
20
21
|
unless resume_job_classes.empty?
|
@@ -32,6 +33,31 @@ module Rukawa
|
|
32
33
|
end
|
33
34
|
end
|
34
35
|
|
36
|
+
def execute
|
37
|
+
dataflows.each(&:execute)
|
38
|
+
end
|
39
|
+
|
40
|
+
def run(wait_interval = 1)
|
41
|
+
promise = Concurrent::Promise.new do
|
42
|
+
futures = execute
|
43
|
+
until futures.all?(&:complete?)
|
44
|
+
yield self if block_given?
|
45
|
+
sleep wait_interval
|
46
|
+
end
|
47
|
+
errors = futures.map(&:reason).compact
|
48
|
+
|
49
|
+
unless errors.empty?
|
50
|
+
errors.each do |err|
|
51
|
+
next if err.is_a?(DependencyUnsatisfied)
|
52
|
+
Rukawa.logger.error(err)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
futures
|
57
|
+
end
|
58
|
+
promise.execute
|
59
|
+
end
|
60
|
+
|
35
61
|
def started_at
|
36
62
|
@dag.nodes.min_by { |j| j.started_at ? j.started_at.to_i : Float::INFINITY }.started_at
|
37
63
|
end
|
data/lib/rukawa/overview.rb
CHANGED
@@ -6,7 +6,7 @@ module Rukawa
|
|
6
6
|
header << "Dependencies" if with_jobs
|
7
7
|
table = Terminal::Table.new headings: header do |t|
|
8
8
|
JobNet.descendants.each do |job_net|
|
9
|
-
list_table_row(t, job_net,
|
9
|
+
list_table_row(t, job_net, with_jobs: with_jobs)
|
10
10
|
end
|
11
11
|
end
|
12
12
|
puts table
|
@@ -23,7 +23,7 @@ module Rukawa
|
|
23
23
|
puts table
|
24
24
|
end
|
25
25
|
|
26
|
-
def list_table_row(table, job_net,
|
26
|
+
def list_table_row(table, job_net, with_jobs: false)
|
27
27
|
row = [Paint[job_net.name, :bold, :underline], job_net.desc]
|
28
28
|
row << "" if with_jobs
|
29
29
|
table << row
|
data/lib/rukawa/runner.rb
CHANGED
@@ -12,33 +12,28 @@ module Rukawa
|
|
12
12
|
|
13
13
|
def initialize(root_job_net)
|
14
14
|
@root_job_net = root_job_net
|
15
|
-
@errors = []
|
16
15
|
end
|
17
16
|
|
18
17
|
def run(batch_mode = false, refresh_interval = DEFAULT_REFRESH_INTERVAL)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
18
|
+
displayed_at = Time.at(0)
|
19
|
+
promise = @root_job_net.run do
|
20
|
+
unless batch_mode
|
21
|
+
if Time.now - displayed_at >= refresh_interval
|
22
|
+
displayed_at = Time.now
|
23
|
+
Overview.display_running_status(@root_job_net)
|
24
|
+
end
|
25
|
+
end
|
25
26
|
end
|
26
|
-
|
27
|
+
futures = promise.value
|
27
28
|
|
28
29
|
Overview.display_running_status(@root_job_net) unless batch_mode
|
29
30
|
puts "Finished #{@root_job_net.name} in #{@root_job_net.formatted_elapsed_time_from}"
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
next if err.is_a?(DependencyUnsatisfied)
|
36
|
-
Rukawa.logger.error(err)
|
37
|
-
end
|
38
|
-
return false
|
32
|
+
if futures.all?(&:fulfilled?)
|
33
|
+
true
|
34
|
+
else
|
35
|
+
false
|
39
36
|
end
|
40
|
-
|
41
|
-
true
|
42
37
|
end
|
43
38
|
end
|
44
39
|
end
|
data/lib/rukawa/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rukawa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- joker1007
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-06-
|
11
|
+
date: 2016-06-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -171,6 +171,7 @@ files:
|
|
171
171
|
- lib/rukawa/abstract_job.rb
|
172
172
|
- lib/rukawa/cli.rb
|
173
173
|
- lib/rukawa/configuration.rb
|
174
|
+
- lib/rukawa/context.rb
|
174
175
|
- lib/rukawa/dag.rb
|
175
176
|
- lib/rukawa/dependency.rb
|
176
177
|
- lib/rukawa/errors.rb
|
@@ -208,7 +209,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
208
209
|
version: '0'
|
209
210
|
requirements: []
|
210
211
|
rubyforge_project:
|
211
|
-
rubygems_version: 2.
|
212
|
+
rubygems_version: 2.5.1
|
212
213
|
signing_key:
|
213
214
|
specification_version: 4
|
214
215
|
summary: Hyper simple job workflow engine
|