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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e9f4f1e22085cbcfcfafc854b03bc5538ee70044
4
- data.tar.gz: 1644fab37cea4a2b001306a84641dbfb3a8da9e6
3
+ metadata.gz: 34dae79e6a5490afb50c25cd0f1a6784bba6e0da
4
+ data.tar.gz: 3e0df7f16eceb68d984fb0219fa5c7349fb529be
5
5
  SHA512:
6
- metadata.gz: 08a3537bb614bec8ccff3e16443c44f72edae4cfa163821fbc7d2e0367081d4c689024be12c67895c59230024cc3ff6fbb44aae1056b3b7831599a6deeb912e2
7
- data.tar.gz: bca2d4b61780f68ad08598f5e51d5f472438db4fb6dceb7f0d109242d461bd9bc69d19fdce337d9c6eea662e922d04a1a6b8a770167b590132023aff0ffa3cf8
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
 
@@ -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'
@@ -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
- exit 1 unless result
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
@@ -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
 
@@ -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(Rukawa.executor, *depend_dataflows) do |*results|
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(Rukawa.executor, *depend_dataflows) do |*results|
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
- Rukawa.store[self.class] ||= Concurrent::Hash.new
213
- Rukawa.store[self.class][key] = value
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
- Rukawa.semaphore.acquire(resource_count)
222
+ @context.semaphore.acquire(resource_count)
222
223
  yield
223
224
  ensure
224
- Rukawa.semaphore.release(resource_count)
225
+ @context.semaphore.release(resource_count)
225
226
  end
226
227
  end
227
228
  end
@@ -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
@@ -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, job_net.dependencies, with_jobs: with_jobs)
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, level = 0, with_jobs: false)
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
@@ -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
- Rukawa.init
20
- Rukawa.logger.info("=== Start Rukawa ===")
21
- futures = @root_job_net.dataflows.each(&:execute)
22
- until futures.all?(&:complete?)
23
- Overview.display_running_status(@root_job_net) unless batch_mode
24
- sleep refresh_interval
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
- Rukawa.logger.info("=== Finish Rukawa ===")
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
- errors = futures.map(&:reason).compact
32
-
33
- unless errors.empty?
34
- errors.each do |err|
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
@@ -1,3 +1,3 @@
1
1
  module Rukawa
2
- VERSION = "0.5.1"
2
+ VERSION = "0.6.0"
3
3
  end
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.5.1
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-18 00:00:00.000000000 Z
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.6.4
212
+ rubygems_version: 2.5.1
212
213
  signing_key:
213
214
  specification_version: 4
214
215
  summary: Hyper simple job workflow engine