ntl-orchestra 0.9.1 → 0.9.2

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
- ---
2
- SHA1:
3
- metadata.gz: c39c9dc0144c1c80a6a7a2bf82769fbfb1e17603
4
- data.tar.gz: b58e51cb70edf817f0ff32efd3fa09e9753e1193
5
- SHA512:
6
- metadata.gz: b10b097ed0729846e3ff79f43798efd3ca2ce25c6dd4f3b08f6571d43ee6add23152ff87f469dd2e55bd114ae0bcffd242f3baf6ea2435356a44ad51cbf938f6
7
- data.tar.gz: 94b4a02725e1a1b12dc11d864bf462882927637b98e283cef9303dab5c1f5a6e077223f158c4b4ccabb82faaa5c92d50f2a6d611ee4c8ec78e2a101000f51ed4
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7a3c2a8f906bac033bc49fd31c5c785d61fcc665
4
+ data.tar.gz: b7909a5e4a439b36f0e133a98356a176fe31f31d
5
+ SHA512:
6
+ metadata.gz: b29d023f1ec08bd492365f926d328aa2bc8568d92e67bfb030dbe9807935a465efbc15eb4a95da256aac47590ab0a23c103e07196a4d2a2526e832b46db15ea0
7
+ data.tar.gz: 191c785e486a990ea5a30284f14098174de61f0f55dfb416b5ca5fdee5d4ad95a7dfff89225ff4b95fdd8ca13bffacef488253e162deb37fdfc4f6a46f3afcd4
data/README.md CHANGED
@@ -296,7 +296,7 @@ Orchestra::Operation.new do
296
296
  end
297
297
  ```
298
298
 
299
- The third is a minor variation of the second. The only difference is that the operation will always return `true`. `finally` makes sense for operations that perform side effects (e.g. Command objects), wherease `result` will make sense for queries.
299
+ The third is a minor variation of the second. The only difference is that the operation will always return `true`. `finally` makes sense for operations that perform side effects (e.g. Command objects), whereas `result` will make sense for queries.
300
300
 
301
301
  ```ruby
302
302
  Orchestra::Operation.new do
@@ -493,7 +493,7 @@ Embedded performances will inherit the observers of the outer operation.
493
493
 
494
494
  ## Recording and playing back services
495
495
 
496
- The final main feature of Orchestra is the ability to record the service calls throughout an operation. These recordings can then be used to replay operations. This could be helpful, for instance, to attach to exceptions in your exception logging service so that programmers can replay failed performances on their development environments. In addition, these recordings could be used to drive integration testing. Thus, instead of using separate tools such as like ActiveRecord fixtures, FactoryGirl, and VCR for every service dependency, you can test your operations with one single setup artifact.
496
+ The final main feature of Orchestra is the ability to record the service calls throughout an operation. These recordings can then be used to replay operations. This could be helpful, for instance, to attach to exceptions in your exception logging service so that programmers can replay failed performances on their development environments. In addition, these recordings could be used to drive integration testing. Thus, instead of using separate tools such as ActiveRecord fixtures, FactoryGirl, and VCR for every service dependency, you can test your operations with one single setup artifact.
497
497
 
498
498
  You can record a performance on any `Conductor` by calling `#record` instead of `#perform`:
499
499
 
@@ -15,7 +15,7 @@ module Orchestra
15
15
  def initialize args = {}
16
16
  @timeout, _ = Util.extract_key_args args, :timeout_ms => 1000
17
17
  @threads = Set.new
18
- @dead_pool = Set.new
18
+ @dying = Queue.new
19
19
  @pool_lock = Mutex.new
20
20
  @queue = Queue.new
21
21
  @jobs = {}
@@ -70,34 +70,49 @@ module Orchestra
70
70
  end
71
71
 
72
72
  def update event, *;
73
- reap_dead_pool if event == :failed
74
- end
75
-
76
- def with_timeout &block
77
- Timeout.timeout Rational(timeout, 1000), &block
73
+ return unless event == :failed
74
+ reap_thread
78
75
  end
79
76
 
80
77
  private
81
78
 
82
79
  def add_thread!
83
- wait_for_thread_count_to_change do
84
- thr = Thread.new &method(:thread_loop)
85
- @threads << thr
86
- end
80
+ old_count = queue.num_waiting
81
+ thr = Thread.new &method(:thread_loop)
82
+ Thread.pass while thr.status == 'run'
83
+ @threads << thr
87
84
  true
88
85
  end
89
86
 
90
- def reap_dead_pool
91
- @dead_pool.each &:join
92
- @dead_pool.clear
93
- end
94
-
95
87
  def remove_thread!
96
- wait_for_thread_count_to_change do queue << :terminate end
97
- sleep Rational(1, 10000) # FIXME
88
+ queue << :terminate
89
+ reap_thread
98
90
  true
99
91
  end
100
92
 
93
+ def reap_thread
94
+ thread = @dying.pop
95
+ @threads.delete thread
96
+ thread.join
97
+ end
98
+
99
+ def thread_loop
100
+ Thread.current.abort_on_exception = false
101
+ until (job = queue.pop) == :terminate
102
+ job.perform
103
+ Thread.pass
104
+ end
105
+ rescue => error
106
+ add_thread!
107
+ job.set_error error
108
+ ensure
109
+ @dying << Thread.current
110
+ end
111
+
112
+ def while_locked &block
113
+ @pool_lock.synchronize &block
114
+ end
115
+
101
116
  class Job
102
117
  include Observable
103
118
 
@@ -136,28 +151,5 @@ module Orchestra
136
151
  Failed = Module.new
137
152
  end
138
153
 
139
- def thread_loop
140
- Thread.current.abort_on_exception = false
141
- until (job = queue.pop) == :terminate
142
- job.perform
143
- end
144
- rescue => error
145
- add_thread!
146
- job.set_error error
147
- ensure
148
- @threads.delete Thread.current
149
- @dead_pool << Thread.current
150
- end
151
-
152
- def wait_for_thread_count_to_change
153
- old_count = queue.num_waiting
154
- yield
155
- ensure
156
- Thread.pass while queue.num_waiting == old_count
157
- end
158
-
159
- def while_locked &block
160
- @pool_lock.synchronize do with_timeout &block end
161
- end
162
154
  end
163
155
  end
@@ -1,3 +1,3 @@
1
1
  module Orchestra
2
- VERSION = "0.9.1" unless defined? VERSION
2
+ VERSION = "0.9.2" unless defined? VERSION
3
3
  end
@@ -20,15 +20,19 @@ class MultithreadingTest < Minitest::Test
20
20
  end
21
21
 
22
22
  def test_multithreading
23
- list = (1..100).to_a
23
+ list = (1..1000).to_a
24
24
 
25
25
  thread_ids = @conductor.perform @operation, :list => list
26
26
 
27
- assert thread_ids.uniq.size > 2, "performance must be spread across threads"
27
+ assert_equal(
28
+ @conductor.thread_count,
29
+ thread_ids.uniq.size,
30
+ "performance must be spread across threads",
31
+ )
28
32
  end
29
33
 
30
34
  def test_exception_during_multithreading
31
- list = (1..100).to_a
35
+ list = (1..50).to_a
32
36
  list[23] = :blow_up
33
37
 
34
38
  assert_raises CustomError do
@@ -2,6 +2,7 @@ class ThreadPoolTest < Minitest::Test
2
2
  def setup
3
3
  @thread_pool = Orchestra::ThreadPool.new
4
4
  @thread_pool.count = 5
5
+ @iterations = Integer(ENV['THREAD_POOL_ITERATIONS'] || 50)
5
6
  end
6
7
 
7
8
  def teardown
@@ -14,7 +15,7 @@ class ThreadPoolTest < Minitest::Test
14
15
  end
15
16
 
16
17
  def test_shutting_down
17
- 100.times do |idx|
18
+ @iterations.times do |idx|
18
19
  assert_equal 5, @thread_pool.count
19
20
  begin
20
21
  @thread_pool.shutdown
@@ -28,23 +29,26 @@ class ThreadPoolTest < Minitest::Test
28
29
  end
29
30
 
30
31
  def test_adjusting_thread_count_is_robust
31
- iterate = lambda { |delta|
32
+ iterate = lambda { |delta, idx|
32
33
  old_count = @thread_pool.count
33
34
  new_count = old_count + delta
34
- expected_status = ['sleep'] * new_count
35
35
  @thread_pool.count = new_count
36
- assert_equal expected_status, @thread_pool.status, "going from #{old_count} ⇒ #{new_count}"
36
+ assert_equal(
37
+ new_count,
38
+ @thread_pool.count,
39
+ "going from #{old_count} ⇒ #{new_count}; size is #{@thread_pool.count}, idx=#{idx}",
40
+ )
37
41
  }
38
42
 
39
- # Add 100 times
40
- 100.times do iterate.call 1 end
41
-
42
- # Remove 100 times
43
- 100.times do iterate.call -1 end
43
+ # Add/remove @iteration times
44
+ @iterations.times do |idx|
45
+ iterate.call 1, idx
46
+ iterate.call -1, idx
47
+ end
44
48
  end
45
49
 
46
50
  def test_performing_work
47
- 100.times do
51
+ @iterations.times do
48
52
  result = @thread_pool.perform do :deadbeef end
49
53
 
50
54
  assert_equal :deadbeef, result
@@ -52,22 +56,22 @@ class ThreadPoolTest < Minitest::Test
52
56
  end
53
57
 
54
58
  def test_enqueueing_work
55
- jobs = 100.times.map do |num|
59
+ jobs = @iterations.times.map do |num|
56
60
  @thread_pool.enqueue do (num + 1) * 2 end
57
61
  end
58
62
 
59
63
  result = jobs.map &:wait
60
64
 
61
- assert_equal 100, result.uniq.size
62
- assert_equal 2, result.first
63
- assert_equal 200, result.last
65
+ assert_equal @iterations, result.uniq.size
66
+ assert_equal 2, result.first
67
+ assert_equal @iterations * 2, result.last
64
68
  end
65
69
 
66
70
  def test_handling_exceptions
67
71
  Thread.current.abort_on_exception = false
68
72
  old_thread_count = @thread_pool.count
69
73
 
70
- input = 100.times.to_a
74
+ input = @iterations.times.to_a
71
75
  input << nil
72
76
 
73
77
  10.times do
@@ -78,7 +82,7 @@ class ThreadPoolTest < Minitest::Test
78
82
  end
79
83
  end
80
84
 
81
- assert_equal ['sleep'] * old_thread_count, @thread_pool.status
85
+ assert_equal old_thread_count, @thread_pool.count
82
86
  end
83
87
 
84
88
  def test_observing_jobs
metadata CHANGED
@@ -1,80 +1,66 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: ntl-orchestra
3
- version: !ruby/object:Gem::Version
4
- version: 0.9.1
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.2
5
5
  platform: ruby
6
- authors:
6
+ authors:
7
7
  - ntl
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-03 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
11
+
12
+ date: 2014-12-04 00:00:00 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - &id003
18
+ - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: "0"
21
+ prerelease: false
14
22
  name: invokr
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
23
+ version_requirements: *id001
20
24
  type: :runtime
25
+ - !ruby/object:Gem::Dependency
26
+ requirement: &id002 !ruby/object:Gem::Requirement
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ version: "1.6"
21
31
  prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
- - !ruby/object:Gem::Dependency
28
32
  name: bundler
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '1.6'
33
+ version_requirements: *id002
34
34
  type: :development
35
+ - !ruby/object:Gem::Dependency
36
+ requirement: &id004 !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - *id003
35
39
  prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '1.6'
41
- - !ruby/object:Gem::Dependency
42
40
  name: pry
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
41
+ version_requirements: *id004
48
42
  type: :development
43
+ - !ruby/object:Gem::Dependency
44
+ requirement: &id005 !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ~>
47
+ - !ruby/object:Gem::Version
48
+ version: "10.0"
49
49
  prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- - !ruby/object:Gem::Dependency
56
50
  name: rake
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '10.0'
51
+ version_requirements: *id005
62
52
  type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '10.0'
69
- description: Orchestra is an orchestration framework for designing complex operations
70
- in an object oriented fashion.
71
- email:
53
+ description: Orchestra is an orchestration framework for designing complex operations in an object oriented fashion.
54
+ email:
72
55
  - nathanladd+github@gmail.com
73
56
  executables: []
57
+
74
58
  extensions: []
59
+
75
60
  extra_rdoc_files: []
76
- files:
77
- - ".gitignore"
61
+
62
+ files:
63
+ - .gitignore
78
64
  - Gemfile
79
65
  - LICENSE.txt
80
66
  - README.md
@@ -117,30 +103,29 @@ files:
117
103
  - test/unit/util_test.rb
118
104
  - tmp/.keep
119
105
  homepage: https://github.com/ntl/orchestra
120
- licenses:
106
+ licenses:
121
107
  - MIT
122
108
  metadata: {}
109
+
123
110
  post_install_message:
124
111
  rdoc_options: []
125
- require_paths:
112
+
113
+ require_paths:
126
114
  - lib
127
- required_ruby_version: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - ">="
130
- - !ruby/object:Gem::Version
131
- version: '0'
132
- required_rubygems_version: !ruby/object:Gem::Requirement
133
- requirements:
134
- - - ">="
135
- - !ruby/object:Gem::Version
136
- version: '0'
115
+ required_ruby_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - *id003
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - *id003
137
121
  requirements: []
122
+
138
123
  rubyforge_project:
139
124
  rubygems_version: 2.2.2
140
125
  signing_key:
141
126
  specification_version: 4
142
127
  summary: Orchestrate complex operations with ease.
143
- test_files:
128
+ test_files:
144
129
  - test/examples/fizz_buzz.rb
145
130
  - test/examples/invitation_service.rb
146
131
  - test/integration/multithreading_test.rb