async 1.12.0 → 1.13.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 +4 -4
- data/.travis.yml +3 -1
- data/README.md +207 -18
- data/Rakefile +1 -0
- data/lib/async.rb +7 -1
- data/lib/async/logger.rb +131 -2
- data/lib/async/node.rb +3 -3
- data/lib/async/queue.rb +2 -0
- data/lib/async/reactor.rb +8 -8
- data/lib/async/task.rb +64 -34
- data/lib/async/terminal.rb +99 -0
- data/lib/async/version.rb +1 -1
- data/lib/async/wrapper.rb +1 -5
- data/spec/async/condition_examples.rb +1 -1
- data/spec/async/logger_spec.rb +48 -4
- data/spec/async/performance_spec.rb +2 -2
- data/spec/async/reactor/nested_spec.rb +4 -4
- data/spec/async/reactor_spec.rb +8 -8
- data/spec/async/task_spec.rb +91 -19
- data/spec/async/wrapper_spec.rb +11 -9
- data/spec/enumerator_spec.rb +5 -5
- metadata +4 -3
@@ -26,9 +26,9 @@ RSpec.describe Async::Reactor do
|
|
26
26
|
outer_reactor = Async::Task.current.reactor
|
27
27
|
inner_reactor = nil
|
28
28
|
|
29
|
-
|
29
|
+
described_class.run do |task|
|
30
30
|
inner_reactor = task.reactor
|
31
|
-
end
|
31
|
+
end
|
32
32
|
|
33
33
|
expect(outer_reactor).to be_kind_of(described_class)
|
34
34
|
expect(outer_reactor).to be_eql(inner_reactor)
|
@@ -40,9 +40,9 @@ RSpec.describe Async::Reactor do
|
|
40
40
|
expect(Async::Task.current?).to be_nil
|
41
41
|
inner_reactor = nil
|
42
42
|
|
43
|
-
|
43
|
+
described_class.run do |task|
|
44
44
|
inner_reactor = task.reactor
|
45
|
-
end
|
45
|
+
end
|
46
46
|
|
47
47
|
expect(inner_reactor).to be_kind_of(described_class)
|
48
48
|
end
|
data/spec/async/reactor_spec.rb
CHANGED
@@ -75,26 +75,26 @@ RSpec.describe Async::Reactor do
|
|
75
75
|
end
|
76
76
|
it "can't return" do
|
77
77
|
expect do
|
78
|
-
Async
|
78
|
+
Async do |task|
|
79
79
|
return
|
80
|
-
end
|
81
|
-
end.to
|
80
|
+
end.wait
|
81
|
+
end.to raise_exception(LocalJumpError)
|
82
82
|
end
|
83
83
|
|
84
84
|
it "is closed after running" do
|
85
85
|
reactor = nil
|
86
86
|
|
87
|
-
Async
|
87
|
+
Async do |task|
|
88
88
|
reactor = task.reactor
|
89
89
|
end
|
90
90
|
|
91
91
|
expect(reactor).to be_closed
|
92
92
|
|
93
|
-
expect{reactor.run}.to
|
93
|
+
expect{reactor.run}.to raise_exception(RuntimeError, /closed/)
|
94
94
|
end
|
95
95
|
|
96
96
|
it "should return a task" do
|
97
|
-
result = Async
|
97
|
+
result = Async do |task|
|
98
98
|
end
|
99
99
|
|
100
100
|
expect(result).to be_kind_of(Async::Task)
|
@@ -153,8 +153,8 @@ RSpec.describe Async::Reactor do
|
|
153
153
|
task.timeout(0.0, timeout_class) do
|
154
154
|
task.sleep(1.0)
|
155
155
|
end
|
156
|
-
end
|
157
|
-
end.to
|
156
|
+
end.wait
|
157
|
+
end.to raise_exception(timeout_class)
|
158
158
|
end
|
159
159
|
end
|
160
160
|
|
data/spec/async/task_spec.rb
CHANGED
@@ -28,7 +28,7 @@ RSpec.describe Async::Task do
|
|
28
28
|
task = reactor.async do |task|
|
29
29
|
end
|
30
30
|
|
31
|
-
expect{task.run}.to
|
31
|
+
expect{task.run}.to raise_exception(RuntimeError, /already running/)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
@@ -54,13 +54,61 @@ RSpec.describe Async::Task do
|
|
54
54
|
end.wait
|
55
55
|
end.wait
|
56
56
|
end
|
57
|
+
|
58
|
+
it "can raise exceptions" do
|
59
|
+
expect do
|
60
|
+
reactor.async do |task|
|
61
|
+
raise "boom"
|
62
|
+
end.wait
|
63
|
+
end.to raise_exception RuntimeError, /boom/
|
64
|
+
end
|
65
|
+
|
66
|
+
it "can raise exception after asynchronous operation" do
|
67
|
+
task = nil
|
68
|
+
|
69
|
+
expect do
|
70
|
+
task = reactor.async do |task|
|
71
|
+
task.sleep 0.1
|
72
|
+
|
73
|
+
raise "boom"
|
74
|
+
end
|
75
|
+
end.to_not raise_exception
|
76
|
+
|
77
|
+
reactor.run do
|
78
|
+
expect do
|
79
|
+
task.wait
|
80
|
+
end.to raise_exception RuntimeError, /boom/
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
it "can consume exceptions" do
|
85
|
+
task = nil
|
86
|
+
|
87
|
+
expect do
|
88
|
+
task = reactor.async(propagate_exceptions: false) do |task|
|
89
|
+
raise "boom"
|
90
|
+
end
|
91
|
+
end.to_not raise_exception
|
92
|
+
|
93
|
+
expect do
|
94
|
+
task.wait
|
95
|
+
end.to raise_exception RuntimeError, /boom/
|
96
|
+
end
|
97
|
+
|
98
|
+
it "won't consume non-StandardError exceptions" do
|
99
|
+
expect do
|
100
|
+
reactor.async(propagate_exceptions: false) do |task|
|
101
|
+
raise SignalException.new(:TERM)
|
102
|
+
end
|
103
|
+
end.to raise_exception(SignalException, /TERM/)
|
104
|
+
end
|
57
105
|
end
|
58
106
|
|
59
107
|
describe '#yield' do
|
60
108
|
it "can yield back to reactor" do
|
61
109
|
state = nil
|
62
110
|
|
63
|
-
|
111
|
+
reactor.async do |task|
|
64
112
|
state = :started
|
65
113
|
task.yield
|
66
114
|
state = :finished
|
@@ -90,7 +138,7 @@ RSpec.describe Async::Task do
|
|
90
138
|
it "should kill direct child" do
|
91
139
|
parent_task = child_task = nil
|
92
140
|
|
93
|
-
|
141
|
+
reactor.async do |task|
|
94
142
|
parent_task = task
|
95
143
|
reactor.async do |task|
|
96
144
|
child_task = task
|
@@ -135,7 +183,7 @@ RSpec.describe Async::Task do
|
|
135
183
|
it "can sleep for the requested duration" do
|
136
184
|
state = nil
|
137
185
|
|
138
|
-
|
186
|
+
reactor.async do |task|
|
139
187
|
task.sleep(duration)
|
140
188
|
state = :finished
|
141
189
|
end
|
@@ -152,10 +200,26 @@ RSpec.describe Async::Task do
|
|
152
200
|
end
|
153
201
|
|
154
202
|
describe '#timeout' do
|
203
|
+
it "can extend timeout" do
|
204
|
+
reactor.async do |task|
|
205
|
+
task.timeout(0.2) do |timer|
|
206
|
+
task.sleep(0.1)
|
207
|
+
|
208
|
+
expect(timer.fires_in).to be_within(10).percent_of(0.1)
|
209
|
+
|
210
|
+
timer.reset
|
211
|
+
|
212
|
+
expect(timer.fires_in).to be_within(10).percent_of(0.2)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
reactor.run
|
217
|
+
end
|
218
|
+
|
155
219
|
it "will timeout if execution takes too long" do
|
156
220
|
state = nil
|
157
221
|
|
158
|
-
|
222
|
+
reactor.async do |task|
|
159
223
|
begin
|
160
224
|
task.timeout(0.01) do
|
161
225
|
state = :started
|
@@ -175,7 +239,7 @@ RSpec.describe Async::Task do
|
|
175
239
|
it "won't timeout if execution completes in time" do
|
176
240
|
state = nil
|
177
241
|
|
178
|
-
|
242
|
+
reactor.async do |task|
|
179
243
|
state = :started
|
180
244
|
task.timeout(0.01) do
|
181
245
|
task.sleep(0.001)
|
@@ -191,8 +255,6 @@ RSpec.describe Async::Task do
|
|
191
255
|
|
192
256
|
describe '#wait' do
|
193
257
|
it "will wait on another task to complete" do
|
194
|
-
result = nil
|
195
|
-
|
196
258
|
apples_task = reactor.async do |task|
|
197
259
|
task.sleep(0.1)
|
198
260
|
|
@@ -205,33 +267,43 @@ RSpec.describe Async::Task do
|
|
205
267
|
:oranges
|
206
268
|
end
|
207
269
|
|
208
|
-
|
209
|
-
|
270
|
+
fruit_salad = reactor.async do |task|
|
271
|
+
[apples_task.wait, oranges_task.wait]
|
210
272
|
end
|
211
273
|
|
212
274
|
reactor.run
|
213
275
|
|
214
|
-
expect(
|
276
|
+
expect(fruit_salad.wait).to be == [:apples, :oranges]
|
277
|
+
end
|
278
|
+
|
279
|
+
it "will raise exceptions when checking result" do
|
280
|
+
error_task = nil
|
281
|
+
|
282
|
+
error_task = reactor.async(propagate_exceptions: false) do |task|
|
283
|
+
raise RuntimeError, "brain not provided"
|
284
|
+
end
|
285
|
+
|
286
|
+
expect do
|
287
|
+
error_task.wait
|
288
|
+
end.to raise_exception(RuntimeError, /brain/)
|
215
289
|
end
|
216
290
|
|
217
|
-
it "will propagate exceptions" do
|
291
|
+
it "will propagate exceptions after async operation" do
|
218
292
|
error_task = nil
|
219
293
|
|
220
|
-
error_task = reactor.async do |task|
|
294
|
+
error_task = reactor.async(propagate_exceptions: false) do |task|
|
221
295
|
task.sleep(0.1)
|
222
296
|
|
223
|
-
raise
|
297
|
+
raise "boom"
|
224
298
|
end
|
225
299
|
|
226
300
|
innocent_task = reactor.async do |task|
|
227
|
-
expect{error_task.
|
301
|
+
expect{error_task.wait}.to raise_exception RuntimeError, /boom/
|
228
302
|
end
|
229
303
|
|
230
|
-
|
304
|
+
expect do
|
231
305
|
reactor.run
|
232
|
-
|
233
|
-
retry
|
234
|
-
end
|
306
|
+
end.to_not raise_exception
|
235
307
|
|
236
308
|
expect(error_task).to be_finished
|
237
309
|
expect(innocent_task).to be_finished
|
data/spec/async/wrapper_spec.rb
CHANGED
@@ -46,7 +46,9 @@ RSpec.describe Async::Wrapper do
|
|
46
46
|
end
|
47
47
|
|
48
48
|
it "can timeout if no event occurs" do
|
49
|
-
expect
|
49
|
+
expect do
|
50
|
+
output.wait_readable(0.1)
|
51
|
+
end.to raise_exception(Async::TimeoutError)
|
50
52
|
end
|
51
53
|
|
52
54
|
it "can wait for readability in sequential tasks" do
|
@@ -66,7 +68,7 @@ RSpec.describe Async::Wrapper do
|
|
66
68
|
reactor.async do
|
67
69
|
expect do
|
68
70
|
output.wait_readable
|
69
|
-
end.to
|
71
|
+
end.to raise_exception(Async::Wrapper::Cancelled)
|
70
72
|
end
|
71
73
|
|
72
74
|
expect(output.monitor).to_not be_nil
|
@@ -82,7 +84,7 @@ RSpec.describe Async::Wrapper do
|
|
82
84
|
reactor.async do
|
83
85
|
expect do
|
84
86
|
input.wait_readable
|
85
|
-
end.to
|
87
|
+
end.to raise_exception(Async::Wrapper::Cancelled)
|
86
88
|
end
|
87
89
|
|
88
90
|
# This reproduces the race condition that can occur if two tasks are resumed in sequence.
|
@@ -93,14 +95,14 @@ RSpec.describe Async::Wrapper do
|
|
93
95
|
# Resume task 2:
|
94
96
|
expect do
|
95
97
|
output.resume
|
96
|
-
end.to_not
|
98
|
+
end.to_not raise_exception
|
97
99
|
end
|
98
100
|
|
99
101
|
it "can be cancelled" do
|
100
102
|
reactor.async do
|
101
103
|
expect do
|
102
104
|
input.wait_readable
|
103
|
-
end.to
|
105
|
+
end.to raise_exception(Async::Wrapper::Cancelled)
|
104
106
|
end
|
105
107
|
|
106
108
|
expect(input.monitor).to_not be_nil
|
@@ -121,7 +123,7 @@ RSpec.describe Async::Wrapper do
|
|
121
123
|
reactor.async do
|
122
124
|
expect do
|
123
125
|
input.wait_readable(1)
|
124
|
-
end.to
|
126
|
+
end.to raise_exception(Async::Wrapper::Cancelled)
|
125
127
|
end
|
126
128
|
|
127
129
|
expect(input.monitor.interests).to be == :r
|
@@ -140,7 +142,7 @@ RSpec.describe Async::Wrapper do
|
|
140
142
|
reactor.async do
|
141
143
|
expect do
|
142
144
|
input.wait_readable
|
143
|
-
end.to
|
145
|
+
end.to raise_exception(Async::Wrapper::Cancelled)
|
144
146
|
end
|
145
147
|
|
146
148
|
expect(input.monitor.interests).to be == :r
|
@@ -148,7 +150,7 @@ RSpec.describe Async::Wrapper do
|
|
148
150
|
reactor.async do
|
149
151
|
expect do
|
150
152
|
input.wait_readable
|
151
|
-
end.to
|
153
|
+
end.to raise_exception(Async::Wrapper::WaitError)
|
152
154
|
end
|
153
155
|
end
|
154
156
|
end
|
@@ -193,7 +195,7 @@ RSpec.describe Async::Wrapper do
|
|
193
195
|
|
194
196
|
expect do
|
195
197
|
output.wait_readable
|
196
|
-
end.to
|
198
|
+
end.to raise_exception(IOError, /closed stream/)
|
197
199
|
end
|
198
200
|
end
|
199
201
|
end
|
data/spec/enumerator_spec.rb
CHANGED
@@ -34,7 +34,7 @@ RSpec.describe Enumerator do
|
|
34
34
|
# no fiber really used in internal iterator,
|
35
35
|
# but let this test be here for completness
|
36
36
|
ar = nil
|
37
|
-
Async
|
37
|
+
Async do |task|
|
38
38
|
ar = enum(task).to_a
|
39
39
|
end
|
40
40
|
expect(ar).to be == [1, 2]
|
@@ -42,7 +42,7 @@ RSpec.describe Enumerator do
|
|
42
42
|
|
43
43
|
it "should play well with Enumerator as external iterator", pending: "expected failure" do
|
44
44
|
ar = []
|
45
|
-
Async
|
45
|
+
Async do |task|
|
46
46
|
en = enum(task)
|
47
47
|
ar << en.next
|
48
48
|
ar << en.next
|
@@ -54,15 +54,15 @@ RSpec.describe Enumerator do
|
|
54
54
|
end
|
55
55
|
|
56
56
|
it "should play well with Enumerator.zip(Enumerator) method", pending: "expected failure" do
|
57
|
-
Async
|
57
|
+
Async do |task|
|
58
58
|
ar = [:a, :b, :c, :d].each.zip(enum(task))
|
59
59
|
expect(ar).to be == [[:a, 1], [:b, 2], [:c, nil], [:d, nil]]
|
60
|
-
end
|
60
|
+
end.wait
|
61
61
|
end
|
62
62
|
|
63
63
|
it "should play with explicit Fiber usage", pending: "expected failure" do
|
64
64
|
ar = []
|
65
|
-
Async
|
65
|
+
Async do |task|
|
66
66
|
fib = Fiber.new {
|
67
67
|
Fiber.yield 1
|
68
68
|
task.sleep(0.002)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: async
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.13.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-01-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nio4r
|
@@ -131,6 +131,7 @@ files:
|
|
131
131
|
- lib/async/reactor.rb
|
132
132
|
- lib/async/semaphore.rb
|
133
133
|
- lib/async/task.rb
|
134
|
+
- lib/async/terminal.rb
|
134
135
|
- lib/async/version.rb
|
135
136
|
- lib/async/wrapper.rb
|
136
137
|
- logo.png
|
@@ -171,7 +172,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
171
172
|
- !ruby/object:Gem::Version
|
172
173
|
version: '0'
|
173
174
|
requirements: []
|
174
|
-
rubygems_version: 3.0.
|
175
|
+
rubygems_version: 3.0.1
|
175
176
|
signing_key:
|
176
177
|
specification_version: 4
|
177
178
|
summary: Async is an asynchronous I/O framework based on nio4r.
|