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,134 +1,134 @@
1
- require 'spec_helper'
2
-
3
- module Concurrent
4
-
5
- describe Event do
6
-
7
- subject{ Event.new }
8
-
9
- context '#initialize' do
10
-
11
- it 'sets the state to unset' do
12
- subject.should_not be_set
13
- end
14
- end
15
-
16
- context '#set?' do
17
-
18
- it 'returns true when the event has been set' do
19
- subject.set
20
- subject.should be_set
21
- end
22
-
23
- it 'returns false if the event is unset' do
24
- subject.reset
25
- subject.should_not be_set
26
- end
27
- end
28
-
29
- context '#set' do
30
-
31
- it 'triggers the event' do
32
- subject.reset
33
- @expected = false
34
- Thread.new{ subject.wait; @expected = true }
35
- sleep(0.1)
36
- subject.set
37
- sleep(0.1)
38
- @expected.should be_true
39
- end
40
-
41
- it 'sets the state to set' do
42
- subject.set
43
- subject.should be_set
44
- end
45
- end
46
-
47
- context '#reset' do
48
-
49
- it 'sets the state to unset' do
50
- subject.set
51
- subject.should be_set
52
- subject.reset
53
- subject.should_not be_set
54
- end
55
- end
56
-
57
- context '#pulse' do
58
-
59
- it 'triggers the event' do
60
- subject.reset
61
- @expected = false
62
- Thread.new{ subject.wait; @expected = true }
63
- sleep(0.1)
64
- subject.pulse
65
- sleep(0.1)
66
- @expected.should be_true
67
- end
68
-
69
- it 'sets the state to unset' do
70
- subject.pulse
71
- sleep(0.1)
72
- subject.should_not be_set
73
- end
74
- end
75
-
76
- context '#wait' do
77
-
78
- it 'returns immediately when the event has been set' do
79
- subject.reset
80
- @expected = false
81
- subject.set
82
- Thread.new{ subject.wait(1000); @expected = true}
83
- sleep(1)
84
- @expected.should be_true
85
- end
86
-
87
- it 'returns true once the event is set' do
88
- subject.set
89
- subject.wait.should be_true
90
- end
91
-
92
- it 'blocks indefinitely when the timer is nil' do
93
- subject.reset
94
- @expected = false
95
- Thread.new{ subject.wait; @expected = true}
96
- subject.set
97
- sleep(1)
98
- @expected.should be_true
99
- end
100
-
101
- it 'stops waiting when the timer expires' do
102
- subject.reset
103
- @expected = false
104
- Thread.new{ subject.wait(0.5); @expected = true}
105
- sleep(1)
106
- @expected.should be_true
107
- end
108
-
109
- it 'returns false when the timer expires' do
110
- subject.reset
111
- subject.wait(1).should be_false
112
- end
113
-
114
- it 'triggers multiple waiting threads' do
115
- subject.reset
116
- @expected = []
117
- 5.times{ Thread.new{ subject.wait; @expected << Thread.current.object_id } }
118
- subject.set
119
- sleep(1)
120
- @expected.length.should eq 5
121
- end
122
-
123
- it 'behaves appropriately if wait begins while #set is processing' do
124
- subject.reset
125
- @expected = []
126
- 5.times{ Thread.new{ subject.wait(5) } }
127
- subject.set
128
- 5.times{ Thread.new{ subject.wait; @expected << Thread.current.object_id } }
129
- sleep(1)
130
- @expected.length.should eq 5
131
- end
132
- end
133
- end
134
- end
1
+ require 'spec_helper'
2
+
3
+ module Concurrent
4
+
5
+ describe Event do
6
+
7
+ subject{ Event.new }
8
+
9
+ context '#initialize' do
10
+
11
+ it 'sets the state to unset' do
12
+ subject.should_not be_set
13
+ end
14
+ end
15
+
16
+ context '#set?' do
17
+
18
+ it 'returns true when the event has been set' do
19
+ subject.set
20
+ subject.should be_set
21
+ end
22
+
23
+ it 'returns false if the event is unset' do
24
+ subject.reset
25
+ subject.should_not be_set
26
+ end
27
+ end
28
+
29
+ context '#set' do
30
+
31
+ it 'triggers the event' do
32
+ subject.reset
33
+ @expected = false
34
+ Thread.new{ subject.wait; @expected = true }
35
+ sleep(0.1)
36
+ subject.set
37
+ sleep(0.1)
38
+ @expected.should be_true
39
+ end
40
+
41
+ it 'sets the state to set' do
42
+ subject.set
43
+ subject.should be_set
44
+ end
45
+ end
46
+
47
+ context '#reset' do
48
+
49
+ it 'sets the state to unset' do
50
+ subject.set
51
+ subject.should be_set
52
+ subject.reset
53
+ subject.should_not be_set
54
+ end
55
+ end
56
+
57
+ context '#pulse' do
58
+
59
+ it 'triggers the event' do
60
+ subject.reset
61
+ @expected = false
62
+ Thread.new{ subject.wait; @expected = true }
63
+ sleep(0.1)
64
+ subject.pulse
65
+ sleep(0.1)
66
+ @expected.should be_true
67
+ end
68
+
69
+ it 'sets the state to unset' do
70
+ subject.pulse
71
+ sleep(0.1)
72
+ subject.should_not be_set
73
+ end
74
+ end
75
+
76
+ context '#wait' do
77
+
78
+ it 'returns immediately when the event has been set' do
79
+ subject.reset
80
+ @expected = false
81
+ subject.set
82
+ Thread.new{ subject.wait(1000); @expected = true}
83
+ sleep(1)
84
+ @expected.should be_true
85
+ end
86
+
87
+ it 'returns true once the event is set' do
88
+ subject.set
89
+ subject.wait.should be_true
90
+ end
91
+
92
+ it 'blocks indefinitely when the timer is nil' do
93
+ subject.reset
94
+ @expected = false
95
+ Thread.new{ subject.wait; @expected = true}
96
+ subject.set
97
+ sleep(1)
98
+ @expected.should be_true
99
+ end
100
+
101
+ it 'stops waiting when the timer expires' do
102
+ subject.reset
103
+ @expected = false
104
+ Thread.new{ subject.wait(0.5); @expected = true}
105
+ sleep(1)
106
+ @expected.should be_true
107
+ end
108
+
109
+ it 'returns false when the timer expires' do
110
+ subject.reset
111
+ subject.wait(1).should be_false
112
+ end
113
+
114
+ it 'triggers multiple waiting threads' do
115
+ subject.reset
116
+ @expected = []
117
+ 5.times{ Thread.new{ subject.wait; @expected << Thread.current.object_id } }
118
+ subject.set
119
+ sleep(1)
120
+ @expected.length.should eq 5
121
+ end
122
+
123
+ it 'behaves appropriately if wait begins while #set is processing' do
124
+ subject.reset
125
+ @expected = []
126
+ 5.times{ Thread.new{ subject.wait(5) } }
127
+ subject.set
128
+ 5.times{ Thread.new{ subject.wait; @expected << Thread.current.object_id } }
129
+ sleep(1)
130
+ @expected.length.should eq 5
131
+ end
132
+ end
133
+ end
134
+ end
@@ -1,200 +1,200 @@
1
- require 'spec_helper'
2
-
3
- module Concurrent
4
-
5
- describe Executor do
6
-
7
- before(:each) do
8
- @orig_stdout = $stdout
9
- $stdout = StringIO.new
10
- end
11
-
12
- after(:each) do
13
- $stdout = @orig_stdout
14
- end
15
-
16
- after(:each) do
17
- @ec.kill unless @ec.nil?
18
- end
19
-
20
- context '#run' do
21
-
22
- it 'raises an exception if no block given' do
23
- lambda {
24
- @ec = Concurrent::Executor.run('Foo')
25
- }.should raise_error
26
- end
27
-
28
- it 'uses the default execution interval when no interval is given' do
29
- @ec = Executor.run('Foo'){ nil }
30
- @ec.execution_interval.should eq Executor::EXECUTION_INTERVAL
31
- end
32
-
33
- it 'uses the default timeout interval when no interval is given' do
34
- @ec = Executor.run('Foo'){ nil }
35
- @ec.timeout_interval.should eq Executor::TIMEOUT_INTERVAL
36
- end
37
-
38
- it 'uses the given execution interval' do
39
- @ec = Executor.run('Foo', execution_interval: 5){ nil }
40
- @ec.execution_interval.should eq 5
41
- end
42
-
43
- it 'uses the given timeout interval' do
44
- @ec = Executor.run('Foo', timeout_interval: 5){ nil }
45
- @ec.timeout_interval.should eq 5
46
- end
47
-
48
- it 'creates a new thread' do
49
- thread = Thread.new{ sleep(1) }
50
- Thread.should_receive(:new).with(any_args()).and_return(thread)
51
- @ec = Executor.run('Foo'){ nil }
52
- end
53
-
54
- it 'returns an ExecutionContext' do
55
- @ec = Executor.run('Foo'){ nil }
56
- @ec.should be_a(Executor::ExecutionContext)
57
- end
58
-
59
- it 'sets the #name context variable' do
60
- @ec = Executor.run('Foo'){ nil }
61
- @ec.name.should eq 'Foo'
62
- end
63
- end
64
-
65
- context 'execution' do
66
-
67
- it 'runs the block immediately when the :run_now option is true' do
68
- @expected = false
69
- @ec = Executor.run('Foo', execution: 500, now: true){ @expected = true }
70
- @expected.should be_false
71
- sleep(1)
72
- @expected.should be_true
73
- end
74
-
75
- it 'waits for :execution_interval seconds when the :run_now option is false' do
76
- @expected = false
77
- @ec = Executor.run('Foo', execution: 0.5, now: false){ @expected = true }
78
- @expected.should be_false
79
- sleep(1)
80
- @expected.should be_true
81
- end
82
-
83
- it 'waits for :execution_interval seconds when the :run_now option is not given' do
84
- @expected = false
85
- @ec = Executor.run('Foo', execution: 0.5){ @expected = true }
86
- @expected.should be_false
87
- sleep(1)
88
- @expected.should be_true
89
- end
90
-
91
- it 'yields to the execution block' do
92
- @expected = false
93
- @ec = Executor.run('Foo', execution: 1){ @expected = true }
94
- sleep(2)
95
- @expected.should be_true
96
- end
97
-
98
- it 'passes any given arguments to the execution block' do
99
- args = [1,2,3,4]
100
- @expected = nil
101
- @ec = Executor.run('Foo', execution_interval: 0.5, args: args) do |*args|
102
- @expected = args
103
- end
104
- sleep(1)
105
- @expected.should eq args
106
- end
107
-
108
- it 'supresses exceptions thrown by the execution block' do
109
- lambda {
110
- @ec = Executor.run('Foo', execution_interval: 0.5) { raise StandardError }
111
- sleep(1)
112
- }.should_not raise_error
113
- end
114
-
115
- it 'kills the worker thread if the timeout is reached' do
116
- # the after(:each) block will trigger this expectation
117
- Thread.should_receive(:kill).at_least(1).with(any_args())
118
- @ec = Executor.run('Foo', execution_interval: 0.5, timeout_interval: 0.5){ Thread.stop }
119
- sleep(1.5)
120
- end
121
- end
122
-
123
- context 'logging' do
124
-
125
- before(:each) do
126
- @name = nil
127
- @level = nil
128
- @msg = nil
129
-
130
- @logger = proc do |name, level, msg|
131
- @name = name
132
- @level = level
133
- @msg = msg
134
- end
135
- end
136
-
137
- it 'uses a custom logger when given' do
138
- @ec = Executor.run('Foo', execution_interval: 0.1, logger: @logger){ nil }
139
- sleep(0.5)
140
- @name.should eq 'Foo'
141
- end
142
-
143
- it 'logs :info when execution is successful' do
144
- @ec = Executor.run('Foo', execution_interval: 0.1, logger: @logger){ nil }
145
- sleep(0.5)
146
- @level.should eq :info
147
- end
148
-
149
- it 'logs :warn when execution times out' do
150
- @ec = Executor.run('Foo', execution_interval: 0.1, timeout_interval: 0.1, logger: @logger){ Thread.stop }
151
- sleep(0.5)
152
- @level.should eq :warn
153
- end
154
-
155
- it 'logs :error when execution is fails' do
156
- @ec = Executor.run('Foo', execution_interval: 0.1, logger: @logger){ raise StandardError }
157
- sleep(0.5)
158
- @level.should eq :error
159
- end
160
- end
161
-
162
- context '#status' do
163
-
164
- it 'returns the status of the executor thread when running' do
165
- @ec = Executor.run('Foo'){ nil }
166
- sleep(0.1)
167
- @ec.status.should eq 'sleep'
168
- end
169
-
170
- it 'returns nil when not running' do
171
- @ec = Executor.run('Foo'){ nil }
172
- @ec.kill
173
- sleep(0.1)
174
- @ec.status.should be_nil
175
- end
176
- end
177
-
178
- context '#join' do
179
-
180
- it 'joins the executor thread when running' do
181
- @ec = Executor.run('Foo'){ nil }
182
- Thread.new{ sleep(1); @ec.kill }
183
- @ec.join.should be_a(Thread)
184
- end
185
-
186
- it 'joins the executor thread with timeout when running' do
187
- @ec = Executor.run('Foo'){ nil }
188
- @ec.join(1).should be_nil
189
- end
190
-
191
- it 'immediately returns nil when not running' do
192
- @ec = Executor.run('Foo'){ nil }
193
- @ec.kill
194
- sleep(0.1)
195
- @ec.join.should be_nil
196
- @ec.join(1).should be_nil
197
- end
198
- end
199
- end
200
- end
1
+ require 'spec_helper'
2
+
3
+ module Concurrent
4
+
5
+ describe Executor do
6
+
7
+ before(:each) do
8
+ @orig_stdout = $stdout
9
+ $stdout = StringIO.new
10
+ end
11
+
12
+ after(:each) do
13
+ $stdout = @orig_stdout
14
+ end
15
+
16
+ after(:each) do
17
+ @ec.kill unless @ec.nil?
18
+ end
19
+
20
+ context '#run' do
21
+
22
+ it 'raises an exception if no block given' do
23
+ lambda {
24
+ @ec = Concurrent::Executor.run('Foo')
25
+ }.should raise_error
26
+ end
27
+
28
+ it 'uses the default execution interval when no interval is given' do
29
+ @ec = Executor.run('Foo'){ nil }
30
+ @ec.execution_interval.should eq Executor::EXECUTION_INTERVAL
31
+ end
32
+
33
+ it 'uses the default timeout interval when no interval is given' do
34
+ @ec = Executor.run('Foo'){ nil }
35
+ @ec.timeout_interval.should eq Executor::TIMEOUT_INTERVAL
36
+ end
37
+
38
+ it 'uses the given execution interval' do
39
+ @ec = Executor.run('Foo', execution_interval: 5){ nil }
40
+ @ec.execution_interval.should eq 5
41
+ end
42
+
43
+ it 'uses the given timeout interval' do
44
+ @ec = Executor.run('Foo', timeout_interval: 5){ nil }
45
+ @ec.timeout_interval.should eq 5
46
+ end
47
+
48
+ it 'creates a new thread' do
49
+ thread = Thread.new{ sleep(1) }
50
+ Thread.should_receive(:new).with(any_args()).and_return(thread)
51
+ @ec = Executor.run('Foo'){ nil }
52
+ end
53
+
54
+ it 'returns an ExecutionContext' do
55
+ @ec = Executor.run('Foo'){ nil }
56
+ @ec.should be_a(Executor::ExecutionContext)
57
+ end
58
+
59
+ it 'sets the #name context variable' do
60
+ @ec = Executor.run('Foo'){ nil }
61
+ @ec.name.should eq 'Foo'
62
+ end
63
+ end
64
+
65
+ context 'execution' do
66
+
67
+ it 'runs the block immediately when the :run_now option is true' do
68
+ @expected = false
69
+ @ec = Executor.run('Foo', execution: 500, now: true){ @expected = true }
70
+ @expected.should be_false
71
+ sleep(1)
72
+ @expected.should be_true
73
+ end
74
+
75
+ it 'waits for :execution_interval seconds when the :run_now option is false' do
76
+ @expected = false
77
+ @ec = Executor.run('Foo', execution: 0.5, now: false){ @expected = true }
78
+ @expected.should be_false
79
+ sleep(1)
80
+ @expected.should be_true
81
+ end
82
+
83
+ it 'waits for :execution_interval seconds when the :run_now option is not given' do
84
+ @expected = false
85
+ @ec = Executor.run('Foo', execution: 0.5){ @expected = true }
86
+ @expected.should be_false
87
+ sleep(1)
88
+ @expected.should be_true
89
+ end
90
+
91
+ it 'yields to the execution block' do
92
+ @expected = false
93
+ @ec = Executor.run('Foo', execution: 1){ @expected = true }
94
+ sleep(2)
95
+ @expected.should be_true
96
+ end
97
+
98
+ it 'passes any given arguments to the execution block' do
99
+ args = [1,2,3,4]
100
+ @expected = nil
101
+ @ec = Executor.run('Foo', execution_interval: 0.5, args: args) do |*args|
102
+ @expected = args
103
+ end
104
+ sleep(1)
105
+ @expected.should eq args
106
+ end
107
+
108
+ it 'supresses exceptions thrown by the execution block' do
109
+ lambda {
110
+ @ec = Executor.run('Foo', execution_interval: 0.5) { raise StandardError }
111
+ sleep(1)
112
+ }.should_not raise_error
113
+ end
114
+
115
+ it 'kills the worker thread if the timeout is reached' do
116
+ # the after(:each) block will trigger this expectation
117
+ Thread.should_receive(:kill).at_least(1).with(any_args())
118
+ @ec = Executor.run('Foo', execution_interval: 0.5, timeout_interval: 0.5){ Thread.stop }
119
+ sleep(1.5)
120
+ end
121
+ end
122
+
123
+ context 'logging' do
124
+
125
+ before(:each) do
126
+ @name = nil
127
+ @level = nil
128
+ @msg = nil
129
+
130
+ @logger = proc do |name, level, msg|
131
+ @name = name
132
+ @level = level
133
+ @msg = msg
134
+ end
135
+ end
136
+
137
+ it 'uses a custom logger when given' do
138
+ @ec = Executor.run('Foo', execution_interval: 0.1, logger: @logger){ nil }
139
+ sleep(0.5)
140
+ @name.should eq 'Foo'
141
+ end
142
+
143
+ it 'logs :info when execution is successful' do
144
+ @ec = Executor.run('Foo', execution_interval: 0.1, logger: @logger){ nil }
145
+ sleep(0.5)
146
+ @level.should eq :info
147
+ end
148
+
149
+ it 'logs :warn when execution times out' do
150
+ @ec = Executor.run('Foo', execution_interval: 0.1, timeout_interval: 0.1, logger: @logger){ Thread.stop }
151
+ sleep(0.5)
152
+ @level.should eq :warn
153
+ end
154
+
155
+ it 'logs :error when execution is fails' do
156
+ @ec = Executor.run('Foo', execution_interval: 0.1, logger: @logger){ raise StandardError }
157
+ sleep(0.5)
158
+ @level.should eq :error
159
+ end
160
+ end
161
+
162
+ context '#status' do
163
+
164
+ it 'returns the status of the executor thread when running' do
165
+ @ec = Executor.run('Foo'){ nil }
166
+ sleep(0.1)
167
+ @ec.status.should eq 'sleep'
168
+ end
169
+
170
+ it 'returns nil when not running' do
171
+ @ec = Executor.run('Foo'){ nil }
172
+ @ec.kill
173
+ sleep(0.1)
174
+ @ec.status.should be_nil
175
+ end
176
+ end
177
+
178
+ context '#join' do
179
+
180
+ it 'joins the executor thread when running' do
181
+ @ec = Executor.run('Foo'){ nil }
182
+ Thread.new{ sleep(1); @ec.kill }
183
+ @ec.join.should be_a(Thread)
184
+ end
185
+
186
+ it 'joins the executor thread with timeout when running' do
187
+ @ec = Executor.run('Foo'){ nil }
188
+ @ec.join(1).should be_nil
189
+ end
190
+
191
+ it 'immediately returns nil when not running' do
192
+ @ec = Executor.run('Foo'){ nil }
193
+ @ec.kill
194
+ sleep(0.1)
195
+ @ec.join.should be_nil
196
+ @ec.join(1).should be_nil
197
+ end
198
+ end
199
+ end
200
+ end