async 1.22.2 → 1.23.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/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
|