concurrent-ruby 0.2.1 → 0.2.2

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.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -21
  3. data/README.md +276 -275
  4. data/lib/concurrent.rb +28 -28
  5. data/lib/concurrent/agent.rb +114 -114
  6. data/lib/concurrent/cached_thread_pool.rb +131 -131
  7. data/lib/concurrent/defer.rb +65 -65
  8. data/lib/concurrent/event.rb +60 -60
  9. data/lib/concurrent/event_machine_defer_proxy.rb +23 -23
  10. data/lib/concurrent/executor.rb +96 -96
  11. data/lib/concurrent/fixed_thread_pool.rb +99 -99
  12. data/lib/concurrent/functions.rb +120 -120
  13. data/lib/concurrent/future.rb +42 -42
  14. data/lib/concurrent/global_thread_pool.rb +24 -16
  15. data/lib/concurrent/goroutine.rb +29 -29
  16. data/lib/concurrent/null_thread_pool.rb +22 -22
  17. data/lib/concurrent/obligation.rb +67 -67
  18. data/lib/concurrent/promise.rb +174 -174
  19. data/lib/concurrent/reactor.rb +166 -166
  20. data/lib/concurrent/reactor/drb_async_demux.rb +83 -83
  21. data/lib/concurrent/reactor/tcp_sync_demux.rb +131 -131
  22. data/lib/concurrent/supervisor.rb +105 -105
  23. data/lib/concurrent/thread_pool.rb +76 -76
  24. data/lib/concurrent/utilities.rb +32 -32
  25. data/lib/concurrent/version.rb +3 -3
  26. data/lib/concurrent_ruby.rb +1 -1
  27. data/md/agent.md +123 -123
  28. data/md/defer.md +174 -174
  29. data/md/event.md +32 -32
  30. data/md/executor.md +187 -187
  31. data/md/future.md +83 -83
  32. data/md/goroutine.md +52 -52
  33. data/md/obligation.md +32 -32
  34. data/md/promise.md +227 -227
  35. data/md/thread_pool.md +224 -224
  36. data/spec/concurrent/agent_spec.rb +390 -386
  37. data/spec/concurrent/cached_thread_pool_spec.rb +125 -125
  38. data/spec/concurrent/defer_spec.rb +199 -195
  39. data/spec/concurrent/event_machine_defer_proxy_spec.rb +256 -256
  40. data/spec/concurrent/event_spec.rb +134 -134
  41. data/spec/concurrent/executor_spec.rb +200 -200
  42. data/spec/concurrent/fixed_thread_pool_spec.rb +83 -83
  43. data/spec/concurrent/functions_spec.rb +217 -217
  44. data/spec/concurrent/future_spec.rb +112 -108
  45. data/spec/concurrent/global_thread_pool_spec.rb +11 -38
  46. data/spec/concurrent/goroutine_spec.rb +67 -67
  47. data/spec/concurrent/null_thread_pool_spec.rb +57 -57
  48. data/spec/concurrent/obligation_shared.rb +132 -132
  49. data/spec/concurrent/promise_spec.rb +316 -312
  50. data/spec/concurrent/reactor/drb_async_demux_spec.rb +196 -196
  51. data/spec/concurrent/reactor/tcp_sync_demux_spec.rb +410 -410
  52. data/spec/concurrent/reactor_spec.rb +364 -364
  53. data/spec/concurrent/supervisor_spec.rb +269 -269
  54. data/spec/concurrent/thread_pool_shared.rb +204 -204
  55. data/spec/concurrent/uses_global_thread_pool_shared.rb +64 -0
  56. data/spec/concurrent/utilities_spec.rb +74 -74
  57. data/spec/spec_helper.rb +32 -32
  58. metadata +17 -19
@@ -1,269 +1,269 @@
1
- require 'spec_helper'
2
-
3
- module Concurrent
4
-
5
- describe Supervisor do
6
-
7
- let(:worker_class) do
8
- Class.new {
9
- behavior(:runnable)
10
- def run() return true; end
11
- def stop() return true; end
12
- def running?() return true; end
13
- }
14
- end
15
-
16
- let(:worker){ worker_class.new }
17
-
18
- subject{ Supervisor.new }
19
-
20
- after(:each) do
21
- subject.stop
22
- end
23
-
24
- context '#initialize' do
25
-
26
- it 'sets the initial length to zero' do
27
- supervisor = Supervisor.new
28
- supervisor.length.should == 0
29
- end
30
-
31
- it 'sets the initial length to one when a worker is provided' do
32
- supervisor = Supervisor.new(worker: worker)
33
- supervisor.length.should == 1
34
- end
35
-
36
- it 'sets the initial state to stopped' do
37
- supervisor = Supervisor.new
38
- supervisor.should_not be_running
39
- end
40
-
41
- it 'sets the monitor interval when given' do
42
- supervisor = Supervisor.new
43
- supervisor.monitor_interval.should == Supervisor::DEFAULT_MONITOR_INTERVAL
44
- end
45
-
46
- it 'sets the monitor interval to the default when not given' do
47
- supervisor = Supervisor.new(monitor_interval: 5)
48
- supervisor.monitor_interval.should == 5
49
-
50
- supervisor = Supervisor.new(monitor: 10)
51
- supervisor.monitor_interval.should == 10
52
- end
53
- end
54
-
55
- context 'run' do
56
-
57
- it 'runs the monitor' do
58
- subject.should_receive(:monitor).with(no_args()).at_least(1).times
59
- t = Thread.new{ subject.run }
60
- sleep(0.1)
61
- subject.stop
62
- Thread.kill(t) unless t.nil?
63
- end
64
-
65
- it 'calls #run on all workers' do
66
- supervisor = Supervisor.new(worker: worker)
67
- # must stub AFTER adding or else #add_worker will reject
68
- worker.should_receive(:run).with(no_args())
69
- t = Thread.new{ supervisor.run }
70
- sleep(0.1)
71
- supervisor.stop
72
- Thread.kill(t)
73
- end
74
-
75
- it 'sets the state to running' do
76
- t = Thread.new{ subject.run }
77
- sleep(0.1)
78
- subject.should be_running
79
- subject.stop
80
- Thread.kill(t)
81
- end
82
-
83
- it 'raises an exception when already running' do
84
- @thread = nil
85
- subject.run!
86
- lambda {
87
- @thread = Thread.new{ subject.run }
88
- @thread.abort_on_exception = true
89
- sleep(0.1)
90
- }.should raise_error(StandardError)
91
- subject.stop
92
- Thread.kill(@thread) unless @thread.nil?
93
- end
94
- end
95
-
96
- context '#run!' do
97
-
98
- it 'runs the monitor thread' do
99
- thread = Thread.new{ nil }
100
- Thread.should_receive(:new).with(no_args()).and_return(thread)
101
- subject.run!
102
- end
103
-
104
- it 'calls #run on all workers' do
105
- supervisor = Supervisor.new(worker: worker)
106
- # must stub AFTER adding or else #add_worker will reject
107
- worker.should_receive(:run).with(no_args())
108
- supervisor.run!
109
- sleep(0.1)
110
- end
111
-
112
- it 'sets the state to running' do
113
- subject.run!
114
- subject.should be_running
115
- end
116
-
117
- it 'raises an exception when already running' do
118
- subject.run!
119
- lambda {
120
- subject.run!
121
- }.should raise_error(StandardError)
122
- end
123
- end
124
-
125
- context '#stop' do
126
-
127
- it 'stops the monitor thread' do
128
- Thread.should_receive(:kill).with(anything())
129
- subject.run!
130
- sleep(0.1)
131
- subject.stop
132
- end
133
-
134
- it 'calls #stop on all workers' do
135
- workers = (1..3).collect{ worker_class.new }
136
- workers.each{|worker| subject.add_worker(worker)}
137
- # must stub AFTER adding or else #add_worker will reject
138
- workers.each{|worker| worker.should_receive(:stop).with(no_args())}
139
- subject.run!
140
- sleep(0.1)
141
- subject.stop
142
- end
143
-
144
- it 'sets the state to stopped' do
145
- subject.run!
146
- subject.stop
147
- subject.should_not be_running
148
- end
149
-
150
- it 'returns true immediately when already stopped' do
151
- subject.stop.should be_true
152
- end
153
-
154
- it 'unblocks a thread blocked by #run and exits normally' do
155
- supervisor = Supervisor.new(monitor: 0.1)
156
- @thread = Thread.new{ sleep(0.5); supervisor.stop }
157
- sleep(0.1)
158
- lambda {
159
- Timeout::timeout(1){ supervisor.run }
160
- }.should_not raise_error
161
- Thread.kill(@thread) unless @thread.nil?
162
- end
163
- end
164
-
165
- context '#running?' do
166
-
167
- it 'returns true when running' do
168
- subject.run!
169
- subject.should be_running
170
- end
171
-
172
- it 'returns false when stopped' do
173
- subject.run!
174
- subject.stop
175
- subject.should_not be_running
176
- end
177
- end
178
-
179
- context '#length' do
180
-
181
- it 'returns a count of attached workers' do
182
- workers = (1..3).collect{ worker.dup }
183
- workers.each{|worker| subject.add_worker(worker)}
184
- subject.length.should == 3
185
- end
186
- end
187
-
188
- context '#add_worker' do
189
-
190
- it 'adds the worker when stopped' do
191
- subject.add_worker(worker)
192
- subject.length.should == 1
193
- end
194
-
195
- it 'rejects the worker when running' do
196
- subject.run!
197
- subject.add_worker(worker)
198
- subject.length.should == 0
199
- end
200
-
201
- it 'rejects a worker without the :runnable behavior' do
202
- subject.add_worker('bogus worker')
203
- subject.length.should == 0
204
- end
205
-
206
- it 'returns true when a worker is accepted' do
207
- subject.add_worker(worker).should be_true
208
- end
209
-
210
- it 'returns false when a worker is not accepted' do
211
- subject.add_worker('bogus worker').should be_false
212
- end
213
- end
214
-
215
- context 'supervision' do
216
-
217
- it 'reruns any worker that stops' do
218
- worker = Class.new(worker_class){
219
- def run() sleep(0.2); end
220
- }.new
221
-
222
- supervisor = Supervisor.new(worker: worker, monitor: 0.1)
223
- supervisor.add_worker(worker)
224
- # must stub AFTER adding or else #add_worker will reject
225
- worker.should_receive(:run).with(no_args()).at_least(2).times
226
- supervisor.run!
227
- sleep(1)
228
- supervisor.stop
229
- end
230
-
231
- it 'reruns any dead threads' do
232
- worker = Class.new(worker_class){
233
- def run() raise StandardError; end
234
- }.new
235
-
236
- supervisor = Supervisor.new(worker: worker, monitor: 0.1)
237
- supervisor.add_worker(worker)
238
- # must stub AFTER adding or else #add_worker will reject
239
- worker.should_receive(:run).with(no_args()).at_least(2).times
240
- supervisor.run!
241
- sleep(1)
242
- supervisor.stop
243
- end
244
- end
245
-
246
- context 'supervisor tree' do
247
-
248
- specify do
249
- s1 = Supervisor.new(monitor: 0.1)
250
- s2 = Supervisor.new(monitor: 0.1)
251
- s3 = Supervisor.new(monitor: 0.1)
252
-
253
- workers = (1..3).collect{ worker_class.new }
254
- workers.each{|worker| s3.add_worker(worker)}
255
- # must stub AFTER adding or else #add_worker will reject
256
- workers.each{|worker| worker.should_receive(:run).with(no_args())}
257
- workers.each{|worker| worker.should_receive(:stop).with(no_args())}
258
-
259
- s1.add_worker(s2)
260
- s2.add_worker(s3)
261
-
262
- s1.run!
263
- sleep(0.1)
264
- s1.stop
265
- sleep(0.1)
266
- end
267
- end
268
- end
269
- end
1
+ require 'spec_helper'
2
+
3
+ module Concurrent
4
+
5
+ describe Supervisor do
6
+
7
+ let(:worker_class) do
8
+ Class.new {
9
+ behavior(:runnable)
10
+ def run() return true; end
11
+ def stop() return true; end
12
+ def running?() return true; end
13
+ }
14
+ end
15
+
16
+ let(:worker){ worker_class.new }
17
+
18
+ subject{ Supervisor.new }
19
+
20
+ after(:each) do
21
+ subject.stop
22
+ end
23
+
24
+ context '#initialize' do
25
+
26
+ it 'sets the initial length to zero' do
27
+ supervisor = Supervisor.new
28
+ supervisor.length.should == 0
29
+ end
30
+
31
+ it 'sets the initial length to one when a worker is provided' do
32
+ supervisor = Supervisor.new(worker: worker)
33
+ supervisor.length.should == 1
34
+ end
35
+
36
+ it 'sets the initial state to stopped' do
37
+ supervisor = Supervisor.new
38
+ supervisor.should_not be_running
39
+ end
40
+
41
+ it 'sets the monitor interval when given' do
42
+ supervisor = Supervisor.new
43
+ supervisor.monitor_interval.should == Supervisor::DEFAULT_MONITOR_INTERVAL
44
+ end
45
+
46
+ it 'sets the monitor interval to the default when not given' do
47
+ supervisor = Supervisor.new(monitor_interval: 5)
48
+ supervisor.monitor_interval.should == 5
49
+
50
+ supervisor = Supervisor.new(monitor: 10)
51
+ supervisor.monitor_interval.should == 10
52
+ end
53
+ end
54
+
55
+ context 'run' do
56
+
57
+ it 'runs the monitor' do
58
+ subject.should_receive(:monitor).with(no_args()).at_least(1).times
59
+ t = Thread.new{ subject.run }
60
+ sleep(0.1)
61
+ subject.stop
62
+ Thread.kill(t) unless t.nil?
63
+ end
64
+
65
+ it 'calls #run on all workers' do
66
+ supervisor = Supervisor.new(worker: worker)
67
+ # must stub AFTER adding or else #add_worker will reject
68
+ worker.should_receive(:run).with(no_args())
69
+ t = Thread.new{ supervisor.run }
70
+ sleep(0.1)
71
+ supervisor.stop
72
+ Thread.kill(t)
73
+ end
74
+
75
+ it 'sets the state to running' do
76
+ t = Thread.new{ subject.run }
77
+ sleep(0.1)
78
+ subject.should be_running
79
+ subject.stop
80
+ Thread.kill(t)
81
+ end
82
+
83
+ it 'raises an exception when already running' do
84
+ @thread = nil
85
+ subject.run!
86
+ lambda {
87
+ @thread = Thread.new{ subject.run }
88
+ @thread.abort_on_exception = true
89
+ sleep(0.1)
90
+ }.should raise_error(StandardError)
91
+ subject.stop
92
+ Thread.kill(@thread) unless @thread.nil?
93
+ end
94
+ end
95
+
96
+ context '#run!' do
97
+
98
+ it 'runs the monitor thread' do
99
+ thread = Thread.new{ nil }
100
+ Thread.should_receive(:new).with(no_args()).and_return(thread)
101
+ subject.run!
102
+ end
103
+
104
+ it 'calls #run on all workers' do
105
+ supervisor = Supervisor.new(worker: worker)
106
+ # must stub AFTER adding or else #add_worker will reject
107
+ worker.should_receive(:run).with(no_args())
108
+ supervisor.run!
109
+ sleep(0.1)
110
+ end
111
+
112
+ it 'sets the state to running' do
113
+ subject.run!
114
+ subject.should be_running
115
+ end
116
+
117
+ it 'raises an exception when already running' do
118
+ subject.run!
119
+ lambda {
120
+ subject.run!
121
+ }.should raise_error(StandardError)
122
+ end
123
+ end
124
+
125
+ context '#stop' do
126
+
127
+ it 'stops the monitor thread' do
128
+ Thread.should_receive(:kill).with(anything())
129
+ subject.run!
130
+ sleep(0.1)
131
+ subject.stop
132
+ end
133
+
134
+ it 'calls #stop on all workers' do
135
+ workers = (1..3).collect{ worker_class.new }
136
+ workers.each{|worker| subject.add_worker(worker)}
137
+ # must stub AFTER adding or else #add_worker will reject
138
+ workers.each{|worker| worker.should_receive(:stop).with(no_args())}
139
+ subject.run!
140
+ sleep(0.1)
141
+ subject.stop
142
+ end
143
+
144
+ it 'sets the state to stopped' do
145
+ subject.run!
146
+ subject.stop
147
+ subject.should_not be_running
148
+ end
149
+
150
+ it 'returns true immediately when already stopped' do
151
+ subject.stop.should be_true
152
+ end
153
+
154
+ it 'unblocks a thread blocked by #run and exits normally' do
155
+ supervisor = Supervisor.new(monitor: 0.1)
156
+ @thread = Thread.new{ sleep(0.5); supervisor.stop }
157
+ sleep(0.1)
158
+ lambda {
159
+ Timeout::timeout(1){ supervisor.run }
160
+ }.should_not raise_error
161
+ Thread.kill(@thread) unless @thread.nil?
162
+ end
163
+ end
164
+
165
+ context '#running?' do
166
+
167
+ it 'returns true when running' do
168
+ subject.run!
169
+ subject.should be_running
170
+ end
171
+
172
+ it 'returns false when stopped' do
173
+ subject.run!
174
+ subject.stop
175
+ subject.should_not be_running
176
+ end
177
+ end
178
+
179
+ context '#length' do
180
+
181
+ it 'returns a count of attached workers' do
182
+ workers = (1..3).collect{ worker.dup }
183
+ workers.each{|worker| subject.add_worker(worker)}
184
+ subject.length.should == 3
185
+ end
186
+ end
187
+
188
+ context '#add_worker' do
189
+
190
+ it 'adds the worker when stopped' do
191
+ subject.add_worker(worker)
192
+ subject.length.should == 1
193
+ end
194
+
195
+ it 'rejects the worker when running' do
196
+ subject.run!
197
+ subject.add_worker(worker)
198
+ subject.length.should == 0
199
+ end
200
+
201
+ it 'rejects a worker without the :runnable behavior' do
202
+ subject.add_worker('bogus worker')
203
+ subject.length.should == 0
204
+ end
205
+
206
+ it 'returns true when a worker is accepted' do
207
+ subject.add_worker(worker).should be_true
208
+ end
209
+
210
+ it 'returns false when a worker is not accepted' do
211
+ subject.add_worker('bogus worker').should be_false
212
+ end
213
+ end
214
+
215
+ context 'supervision' do
216
+
217
+ it 'reruns any worker that stops' do
218
+ worker = Class.new(worker_class){
219
+ def run() sleep(0.2); end
220
+ }.new
221
+
222
+ supervisor = Supervisor.new(worker: worker, monitor: 0.1)
223
+ supervisor.add_worker(worker)
224
+ # must stub AFTER adding or else #add_worker will reject
225
+ worker.should_receive(:run).with(no_args()).at_least(2).times
226
+ supervisor.run!
227
+ sleep(1)
228
+ supervisor.stop
229
+ end
230
+
231
+ it 'reruns any dead threads' do
232
+ worker = Class.new(worker_class){
233
+ def run() raise StandardError; end
234
+ }.new
235
+
236
+ supervisor = Supervisor.new(worker: worker, monitor: 0.1)
237
+ supervisor.add_worker(worker)
238
+ # must stub AFTER adding or else #add_worker will reject
239
+ worker.should_receive(:run).with(no_args()).at_least(2).times
240
+ supervisor.run!
241
+ sleep(1)
242
+ supervisor.stop
243
+ end
244
+ end
245
+
246
+ context 'supervisor tree' do
247
+
248
+ specify do
249
+ s1 = Supervisor.new(monitor: 0.1)
250
+ s2 = Supervisor.new(monitor: 0.1)
251
+ s3 = Supervisor.new(monitor: 0.1)
252
+
253
+ workers = (1..3).collect{ worker_class.new }
254
+ workers.each{|worker| s3.add_worker(worker)}
255
+ # must stub AFTER adding or else #add_worker will reject
256
+ workers.each{|worker| worker.should_receive(:run).at_least(1).times.with(no_args())}
257
+ workers.each{|worker| worker.should_receive(:stop).at_least(1).times.with(no_args())}
258
+
259
+ s1.add_worker(s2)
260
+ s2.add_worker(s3)
261
+
262
+ s1.run!
263
+ sleep(0.2)
264
+ s1.stop
265
+ sleep(0.2)
266
+ end
267
+ end
268
+ end
269
+ end