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 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