async 1.10.0 → 1.10.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fc6f62aa8e36dcfa1864f1b34d6f81b220583b511b1e81843cca29ba57669160
4
- data.tar.gz: 0fb3bdc83efe1d7ebb06594d7b85c481d8934e1ba0a73a2858a6e1b772ef2971
3
+ metadata.gz: e0b789abc06e34991f2e29573f377f4c5c2fdc6c11d3d22b33d524ec82a73e23
4
+ data.tar.gz: eafd1a24553091204bf1bf6f0340b9221ae27b28873acf1e3201db3f6859cf3f
5
5
  SHA512:
6
- metadata.gz: 6b9881a10f81214fbea511eb8d4c7fd1d96af8e92dfebb6452604fe4d6ae35dfa667fbace3c600c25ecdbccb6cfdba6dacbc7bba058051a7e7c7d4de4ceb2941
7
- data.tar.gz: 3db5a1c721168949e2aef7dae62aab8efc48e960124e894c112245a7174ccea0487e47fb1794750c5434ed192e357cbd19b705b9ebd72992a4b03801754e254d
6
+ metadata.gz: fcc907cf78c1c61a01acf1ee54473c80c73456796d372e7940104aafaed78c1cb8b7a506185227ebcf74fe1d54116c882f1f4fb5039920f9df4f678ef3c2193f
7
+ data.tar.gz: d9c4d25e9b9dc60367954a803a9581ac865550bccf229471a7a9cfc171e8d4b50ee2df5c35ed71116f6947c367f8072a7c9ca506e26322f131ace226e816dd14
@@ -21,9 +21,11 @@ matrix:
21
21
  - rvm: 2.6
22
22
  - rvm: jruby-head
23
23
  env: JRUBY_OPTS="--debug -X+O"
24
+ - rvm: truffleruby
24
25
  - rvm: ruby-head
25
26
  - rvm: rbx-3
26
27
  allow_failures:
27
28
  - rvm: ruby-head
28
29
  - rvm: jruby-head
29
30
  - rvm: rbx-3
31
+ - rvm: truffleruby
data/README.md CHANGED
@@ -105,28 +105,11 @@ end
105
105
 
106
106
  As tasks run synchronously until they yield back to the reactor, you can guarantee this model works correctly. While in theory `IO#autoclose` allows you to automatically close file descriptors when they go out of scope via the GC, it may produce unpredictable behavour (exhaustion of file descriptors, flushing data at odd times), so it's not recommended.
107
107
 
108
- ## Supported Ruby Versions
108
+ ## Caveats
109
109
 
110
- This library aims to support and is [tested against][travis] the following Ruby
111
- versions:
110
+ ### Enumerators
112
111
 
113
- * Ruby 2.2+
114
- * JRuby 9.1.6.0+
115
-
116
- If something doesn't work on one of these versions, it's a bug.
117
-
118
- This library may inadvertently work (or seem to work) on other Ruby versions,
119
- however support will only be provided for the versions listed above.
120
-
121
- If you would like this library to support another Ruby version or
122
- implementation, you may volunteer to be a maintainer. Being a maintainer
123
- entails making sure all tests run and pass on that implementation. When
124
- something breaks on your implementation, you will be responsible for providing
125
- patches in a timely fashion. If critical issues for a particular implementation
126
- exist at the time of a major release, support for that Ruby version may be
127
- dropped.
128
-
129
- [travis]: http://travis-ci.org/socketry/async
112
+ Due to limitations within Ruby and the nature of this library, it is not possible to use `to_enum` on methods which invoke asynchronous behavior. We hope to [fix this issue in the future](https://github.com/socketry/async/issues/23).
130
113
 
131
114
  ## Contributing
132
115
 
data/Rakefile CHANGED
@@ -6,14 +6,18 @@ RSpec::Core::RakeTask.new(:test)
6
6
  task :default => :test
7
7
 
8
8
  def clone_and_test(name)
9
- sh("git clone https://git@github.com/socketry/#{name}")
9
+ path = "external/#{name}"
10
+ FileUtils.rm_rf path
11
+ FileUtils.mkdir_p path
12
+
13
+ sh("git clone https://git@github.com/socketry/#{name} #{path}")
10
14
 
11
15
  # I tried using `bundle config --local local.async ../` but it simply doesn't work.
12
- File.open("#{name}/Gemfile", "a") do |file|
13
- file.puts('gem "async", path: "../"')
16
+ File.open("#{path}/Gemfile", "a") do |file|
17
+ file.puts('gem "async", path: "../../"')
14
18
  end
15
19
 
16
- sh("cd #{name} && bundle install && bundle exec rake test")
20
+ sh("cd #{path} && bundle install && bundle exec rake test")
17
21
  end
18
22
 
19
23
  task :external do
@@ -65,6 +65,7 @@ module Async
65
65
  @timers = Timers::Group.new
66
66
 
67
67
  @ready = []
68
+ @running = []
68
69
 
69
70
  @stopped = true
70
71
  end
@@ -135,7 +136,7 @@ module Async
135
136
  end
136
137
 
137
138
  def finished?
138
- super && @ready.empty?
139
+ super && @ready.empty? && @running.empty?
139
140
  end
140
141
 
141
142
  # Run the reactor until either all tasks complete or {#stop} is invoked.
@@ -149,15 +150,21 @@ module Async
149
150
  initial_task = async(*args, &block) if block_given?
150
151
 
151
152
  @timers.wait do |interval|
152
- if @ready.any?
153
- @ready.each do |fiber|
153
+ # running used to correctly answer on `finished?`, and to reuse Array object.
154
+ @running, @ready = @ready, @running
155
+ if @running.any?
156
+ @running.each do |fiber|
154
157
  fiber.resume if fiber.alive?
155
158
  end
156
-
157
- @ready.clear
158
-
159
- # The above tasks may schedule, cancel or affect timers in some way. We need to compute a new wait interval for the blocking selector call below:
160
- interval = @timers.wait_interval
159
+ @running.clear
160
+
161
+ # if there are tasks ready to execute, don't sleep.
162
+ if @ready.any?
163
+ interval = 0
164
+ else
165
+ # The above tasks may schedule, cancel or affect timers in some way. We need to compute a new wait interval for the blocking selector call below:
166
+ interval = @timers.wait_interval
167
+ end
161
168
  end
162
169
 
163
170
  # - nil: no timers
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Async
22
- VERSION = "1.10.0"
22
+ VERSION = "1.10.1"
23
23
  end
@@ -50,6 +50,9 @@ module Async
50
50
  end
51
51
 
52
52
  def resume(*args)
53
+ # It's possible that the monitor was closed before calling resume.
54
+ return unless @monitor
55
+
53
56
  readiness = @monitor.readiness
54
57
 
55
58
  if @readable and (readiness == :r or readiness == :rw)
@@ -78,6 +78,24 @@ RSpec.describe Async::Wrapper do
78
78
  expect(input.wait_writable).to be_truthy
79
79
  end
80
80
 
81
+ it "can be cancelled while waiting to be readable" do
82
+ reactor.async do
83
+ expect do
84
+ input.wait_readable
85
+ end.to raise_error(Async::Wrapper::Cancelled)
86
+ end
87
+
88
+ # This reproduces the race condition that can occur if two tasks are resumed in sequence.
89
+
90
+ # Resume task 1 which closes IO:
91
+ output.close
92
+
93
+ # Resume task 2:
94
+ expect do
95
+ output.resume
96
+ end.to_not raise_error
97
+ end
98
+
81
99
  it "can be cancelled" do
82
100
  reactor.async do
83
101
  expect do
@@ -0,0 +1,81 @@
1
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ # Copyright, 2018, by Sokolov Yura aka funny-falcon
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+
22
+ RSpec.describe Enumerator do
23
+ def some_yielder(task)
24
+ yield 1
25
+ task.sleep(0.002)
26
+ yield 2
27
+ end
28
+
29
+ def enum(task)
30
+ to_enum(:some_yielder, task)
31
+ end
32
+
33
+ it "should play well with Enumerator as internal iterator" do
34
+ # no fiber really used in internal iterator,
35
+ # but let this test be here for completness
36
+ ar = nil
37
+ Async::Reactor.run do |task|
38
+ ar = enum(task).to_a
39
+ end
40
+ expect(ar).to be == [1, 2]
41
+ end
42
+
43
+ it "should play well with Enumerator as external iterator", pending: "expected failure" do
44
+ ar = []
45
+ Async::Reactor.run do |task|
46
+ en = enum(task)
47
+ ar << en.next
48
+ ar << en.next
49
+ ar << begin en.next rescue $! end
50
+ end
51
+ expect(ar[0]).to be == 1
52
+ expect(ar[1]).to be == 2
53
+ expect(ar[2]).to be_a StopIteration
54
+ end
55
+
56
+ it "should play well with Enumerator.zip(Enumerator) method", pending: "expected failure" do
57
+ Async::Reactor.run do |task|
58
+ ar = [:a, :b, :c, :d].each.zip(enum(task))
59
+ expect(ar).to be == [[:a, 1], [:b, 2], [:c, nil], [:d, nil]]
60
+ end
61
+ end
62
+
63
+ it "should play with explicit Fiber usage", pending: "expected failure" do
64
+ ar = []
65
+ Async::Reactor.run do |task|
66
+ fib = Fiber.new {
67
+ Fiber.yield 1
68
+ task.sleep(0.002)
69
+ Fiber.yield 2
70
+ }
71
+ ar << fib.resume
72
+ ar << fib.resume
73
+ ar << fib.resume
74
+ ar << begin en.next rescue $! end
75
+ end
76
+ expect(ar[0]).to be == 1
77
+ expect(ar[1]).to be == 2
78
+ expect(ar[2]).to be nil
79
+ expect(ar[3]).to be_a FiberError
80
+ end
81
+ end
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.10.0
4
+ version: 1.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-12 00:00:00.000000000 Z
11
+ date: 2018-08-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nio4r
@@ -149,6 +149,7 @@ files:
149
149
  - spec/async/semaphore_spec.rb
150
150
  - spec/async/task_spec.rb
151
151
  - spec/async/wrapper_spec.rb
152
+ - spec/enumerator_spec.rb
152
153
  - spec/spec_helper.rb
153
154
  homepage: https://github.com/socketry/async
154
155
  licenses:
@@ -188,4 +189,5 @@ test_files:
188
189
  - spec/async/semaphore_spec.rb
189
190
  - spec/async/task_spec.rb
190
191
  - spec/async/wrapper_spec.rb
192
+ - spec/enumerator_spec.rb
191
193
  - spec/spec_helper.rb