rukawa 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|