async 1.22.2 → 1.23.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +17 -0
- data/lib/async/barrier.rb +2 -1
- data/lib/async/node.rb +4 -0
- data/lib/async/reactor.rb +4 -4
- data/lib/async/semaphore.rb +5 -5
- data/lib/async/task.rb +12 -5
- data/lib/async/version.rb +1 -1
- data/spec/async/barrier_spec.rb +14 -0
- data/spec/async/condition_examples.rb +17 -0
- data/spec/async/notification_spec.rb +1 -0
- data/spec/async/task_spec.rb +42 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1dc28a8cd53cda6b82492cf8a1ed3c2a7786f4f6a29da3935be00298e25eaaea
|
4
|
+
data.tar.gz: c70dfa854738d6eccd197f322312ed1ea810378428b08fba18ca24076a5d98d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d305bdc4e707ba26b602809669ba8972017be01b7a599e98c471bf969e434a05b5ef725b3853793f7a82a2e7dc13c89231e383d6b06ffbadb966d77eaa36015a
|
7
|
+
data.tar.gz: 58673e31ac2e10e82062fd2def69e040c7780bf6179eb5092bed365ef3564a61d1553a63b45a151b53b64fe43cea4d7139fe0e844b7755083b13436c0008fd42
|
data/README.md
CHANGED
@@ -307,6 +307,23 @@ Due to limitations within Ruby and the nature of this library, it is not possibl
|
|
307
307
|
|
308
308
|
Blocking Ruby methods such as `pop` in the `Queue` class require access to their own threads and will not yield control back to the reactor which can result in a deadlock. As a substitute for the standard library `Queue`, the `Async::Queue` class can be used.
|
309
309
|
|
310
|
+
## Conventions
|
311
|
+
|
312
|
+
### Nesting Tasks
|
313
|
+
|
314
|
+
`Async::Barrier` and `Async::Semaphore` are designed to be compatible with each other, and with other tasks that nest `#async` invocations. There are other similar situations where you may want to pass in a parent task, e.g. `Async::IO::Endpoint#bind`.
|
315
|
+
|
316
|
+
```ruby
|
317
|
+
barrier = Async::Barrier.new
|
318
|
+
semaphore = Async::Semaphore.new(2)
|
319
|
+
|
320
|
+
semaphore.async(parent: barrier) do
|
321
|
+
# ...
|
322
|
+
end
|
323
|
+
```
|
324
|
+
|
325
|
+
A `parent:` in this context is anything that responds to `#async` in the same way that `Async::Task` responds to `#async`. In situations where you strictly depend on the interface of `Async::Task`, use the `task: Task.current` pattern.
|
326
|
+
|
310
327
|
## Contributing
|
311
328
|
|
312
329
|
1. Fork it
|
data/lib/async/barrier.rb
CHANGED
data/lib/async/node.rb
CHANGED
data/lib/async/reactor.rb
CHANGED
@@ -88,7 +88,7 @@ module Async
|
|
88
88
|
end
|
89
89
|
|
90
90
|
def to_s
|
91
|
-
"
|
91
|
+
"\#<#{self.description} (#{@stopped ? 'stopped' : 'running'})>"
|
92
92
|
end
|
93
93
|
|
94
94
|
# @attr stopped [Boolean]
|
@@ -131,7 +131,7 @@ module Async
|
|
131
131
|
|
132
132
|
return monitor
|
133
133
|
end
|
134
|
-
|
134
|
+
|
135
135
|
# Stop the reactor at the earliest convenience. Can be called from a different thread safely.
|
136
136
|
# @return [void]
|
137
137
|
def stop
|
@@ -169,7 +169,7 @@ module Async
|
|
169
169
|
initial_task = self.async(*args, &block) if block_given?
|
170
170
|
|
171
171
|
until @stopped
|
172
|
-
|
172
|
+
logger.debug(self) {"@ready = #{@ready} @running = #{@running}"}
|
173
173
|
|
174
174
|
if @ready.any?
|
175
175
|
# running used to correctly answer on `finished?`, and to reuse Array object.
|
@@ -200,7 +200,7 @@ module Async
|
|
200
200
|
interval = 0
|
201
201
|
end
|
202
202
|
|
203
|
-
|
203
|
+
logger.debug(self) {"Selecting with #{@children&.size} children with interval = #{interval ? interval.round(2) : 'infinite'}..."}
|
204
204
|
if monitors = @selector.select(interval)
|
205
205
|
monitors.each do |monitor|
|
206
206
|
monitor.value.resume
|
data/lib/async/semaphore.rb
CHANGED
@@ -79,14 +79,14 @@ module Async
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
-
# Release the semaphore. Must match up with a corresponding call to `acquire`.
|
82
|
+
# Release the semaphore. Must match up with a corresponding call to `acquire`. Will release waiting fibers in FIFO order.
|
83
83
|
def release
|
84
84
|
@count -= 1
|
85
85
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
86
|
+
while (@limit - @count) > 0 and fiber = @waiting.shift
|
87
|
+
if fiber.alive?
|
88
|
+
fiber.resume
|
89
|
+
end
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
data/lib/async/task.rb
CHANGED
@@ -85,7 +85,7 @@ module Async
|
|
85
85
|
end
|
86
86
|
|
87
87
|
def to_s
|
88
|
-
"
|
88
|
+
"\#<#{self.description} (#{@status})>"
|
89
89
|
end
|
90
90
|
|
91
91
|
def logger
|
@@ -149,7 +149,7 @@ module Async
|
|
149
149
|
|
150
150
|
# Stop the task and all of its children.
|
151
151
|
# @return [void]
|
152
|
-
def stop
|
152
|
+
def stop(later = false)
|
153
153
|
if self.stopped?
|
154
154
|
# If we already stopped this task... don't try to stop it again:
|
155
155
|
return
|
@@ -157,7 +157,11 @@ module Async
|
|
157
157
|
|
158
158
|
if self.running?
|
159
159
|
if self.current?
|
160
|
-
|
160
|
+
if later
|
161
|
+
@reactor << Stop::Later.new(self)
|
162
|
+
else
|
163
|
+
raise Stop, "Stopping current task!"
|
164
|
+
end
|
161
165
|
elsif @fiber&.alive?
|
162
166
|
begin
|
163
167
|
@fiber.resume(Stop.new)
|
@@ -235,9 +239,12 @@ module Async
|
|
235
239
|
end
|
236
240
|
|
237
241
|
def stop!
|
238
|
-
# logger.debug(self) {"Task was stopped with #{@children.
|
242
|
+
# logger.debug(self) {"Task was stopped with #{@children&.size.inspect} children!"}
|
239
243
|
@status = :stopped
|
240
|
-
|
244
|
+
|
245
|
+
@children&.each do |child|
|
246
|
+
child.stop(true)
|
247
|
+
end
|
241
248
|
end
|
242
249
|
|
243
250
|
def make_fiber(&block)
|
data/lib/async/version.rb
CHANGED
data/spec/async/barrier_spec.rb
CHANGED
@@ -75,6 +75,20 @@ RSpec.describe Async::Barrier do
|
|
75
75
|
|
76
76
|
expect(subject).to be_empty
|
77
77
|
end
|
78
|
+
|
79
|
+
it 'waits for tasks in order' do
|
80
|
+
order = []
|
81
|
+
|
82
|
+
5.times do |i|
|
83
|
+
subject.async do
|
84
|
+
order << i
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
subject.wait
|
89
|
+
|
90
|
+
expect(order).to be == [0, 1, 2, 3, 4]
|
91
|
+
end
|
78
92
|
end
|
79
93
|
|
80
94
|
context 'with semaphore' do
|
@@ -51,6 +51,23 @@ RSpec.shared_examples Async::Condition do
|
|
51
51
|
subject.signal
|
52
52
|
end
|
53
53
|
|
54
|
+
it 'resumes tasks in order' do
|
55
|
+
order = []
|
56
|
+
|
57
|
+
5.times do |i|
|
58
|
+
task = reactor.async do
|
59
|
+
subject.wait
|
60
|
+
order << i
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
subject.signal
|
65
|
+
|
66
|
+
reactor.yield
|
67
|
+
|
68
|
+
expect(order).to be == [0, 1, 2, 3, 4]
|
69
|
+
end
|
70
|
+
|
54
71
|
context "with timeout" do
|
55
72
|
before do
|
56
73
|
@state = nil
|
data/spec/async/task_spec.rb
CHANGED
@@ -181,6 +181,19 @@ RSpec.describe Async::Task do
|
|
181
181
|
expect(task).to be_stopped
|
182
182
|
end
|
183
183
|
|
184
|
+
it "can stop current task using exception" do
|
185
|
+
state = nil
|
186
|
+
|
187
|
+
task = reactor.async do |task|
|
188
|
+
state = :started
|
189
|
+
raise Async::Stop, "I'm finished."
|
190
|
+
state = :finished
|
191
|
+
end
|
192
|
+
|
193
|
+
expect(state).to be == :started
|
194
|
+
expect(task).to be_stopped
|
195
|
+
end
|
196
|
+
|
184
197
|
it "should stop direct child" do
|
185
198
|
parent_task = child_task = nil
|
186
199
|
|
@@ -205,6 +218,35 @@ RSpec.describe Async::Task do
|
|
205
218
|
expect(child_task).to_not be_alive
|
206
219
|
end
|
207
220
|
|
221
|
+
it "can stop nested parent" do
|
222
|
+
parent_task = nil
|
223
|
+
children_tasks = []
|
224
|
+
|
225
|
+
reactor.async do |task|
|
226
|
+
parent_task = task
|
227
|
+
|
228
|
+
reactor.async do |task|
|
229
|
+
children_tasks << task
|
230
|
+
task.sleep(2)
|
231
|
+
end
|
232
|
+
|
233
|
+
reactor.async do |task|
|
234
|
+
children_tasks << task
|
235
|
+
task.sleep(1)
|
236
|
+
parent_task.stop
|
237
|
+
end
|
238
|
+
|
239
|
+
reactor.async do |task|
|
240
|
+
children_tasks << task
|
241
|
+
task.sleep(2)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
reactor.run
|
246
|
+
|
247
|
+
expect(parent_task).to_not be_alive
|
248
|
+
end
|
249
|
+
|
208
250
|
it "should not remove running task" do
|
209
251
|
top_task = middle_task = bottom_task = nil
|
210
252
|
|
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.23.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: 2019-10-
|
11
|
+
date: 2019-10-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nio4r
|