async 2.5.1 → 2.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 862d2b83e50785cb72e11913b43433c48f996176da829a247f7bc777bdec3e4d
4
- data.tar.gz: 3854347d6ad621746deb3420f6fec9e81f6fac6c2f76322c0e1dfccdb6faa628
3
+ metadata.gz: 0f62c8150ba7dba6f26532b080a4c99ecde97d86cf5f31746aec706d12644550
4
+ data.tar.gz: 99bbe4f65da2c18ab75bc67377896b7b6c26f6056eb789ef22d5601f43526228
5
5
  SHA512:
6
- metadata.gz: 9e62e8e2be2aa0f79f122258049850e016190a72fbe5756520ca07250a020f7e656239beaba61cf0a5cd1d948130bab704c6f96370b7870830c737e4872059c9
7
- data.tar.gz: 49fa1924bda3bbe42cc1ab374c70f2d6916c46528343e37d5423cf12864db2a4def8316ba394804acc3197f73d9e461bbb0fc4dc75a4ccf9a5441e46850e417d
6
+ metadata.gz: 3c6a7fee5fb6d429b7533afb80dd38ad499c8dd313ee5f881cdd19479a8f1f28072f16f07f83305f6d2e6ddaa7907859938fcd69e2fc7b0e945b194588fd22e2
7
+ data.tar.gz: f10a739ba6013c928199c4abe884e9dbf9d4d48d7f8329ed3977bb9230584d100505d617a859c113bf04c25cbf9ae4353e525221563f930227467cbaebf153b1
checksums.yaml.gz.sig CHANGED
Binary file
data/lib/async/node.rb CHANGED
@@ -5,6 +5,8 @@
5
5
  # Copyright, 2017, by Kent Gruber.
6
6
  # Copyright, 2022, by Shannon Skipper.
7
7
 
8
+ require 'fiber/annotation'
9
+
8
10
  require_relative 'list'
9
11
 
10
12
  module Async
@@ -109,20 +111,27 @@ module Async
109
111
 
110
112
  def annotate(annotation)
111
113
  if block_given?
112
- previous_annotation = @annotation
113
- @annotation = annotation
114
- yield
115
- @annotation = previous_annotation
114
+ begin
115
+ current_annotation = @annotation
116
+ @annotation = annotation
117
+ return yield
118
+ ensure
119
+ @annotation = current_annotation
120
+ end
116
121
  else
117
122
  @annotation = annotation
118
123
  end
119
124
  end
120
125
 
126
+ def annotation
127
+ @annotation
128
+ end
129
+
121
130
  def description
122
131
  @object_name ||= "#{self.class}:#{format '%#018x', object_id}#{@transient ? ' transient' : nil}"
123
132
 
124
- if @annotation
125
- "#{@object_name} #{@annotation}"
133
+ if annotation = self.annotation
134
+ "#{@object_name} #{annotation}"
126
135
  elsif line = self.backtrace(0, 1)&.first
127
136
  "#{@object_name} #{line}"
128
137
  else
@@ -17,6 +17,12 @@ require 'resolv'
17
17
  module Async
18
18
  # Handles scheduling of fibers. Implements the fiber scheduler interface.
19
19
  class Scheduler < Node
20
+ class ClosedError < RuntimeError
21
+ def initialize(message = "Scheduler is closed!")
22
+ super
23
+ end
24
+ end
25
+
20
26
  # Whether the fiber scheduler is supported.
21
27
  # @public Since `stable-v1`.
22
28
  def self.supported?
@@ -150,6 +156,9 @@ module Async
150
156
 
151
157
  # @asynchronous May be non-blocking..
152
158
  def address_resolve(hostname)
159
+ # On some platforms, hostnames may contain a device-specific suffix (e.g. %en0). We need to strip this before resolving.
160
+ # See <https://github.com/socketry/async/issues/180> for more details.
161
+ hostname = hostname.split("%", 2).first
153
162
  ::Resolv.getaddresses(hostname)
154
163
  end
155
164
 
@@ -233,7 +242,7 @@ module Async
233
242
 
234
243
  # Run the reactor until all tasks are finished. Proxies arguments to {#async} immediately before entering the loop, if a block is provided.
235
244
  def run(...)
236
- Kernel::raise RuntimeError, 'Reactor has been closed' if @selector.nil?
245
+ Kernel::raise ClosedError if @selector.nil?
237
246
 
238
247
  initial_task = self.async(...) if block_given?
239
248
 
@@ -260,6 +269,8 @@ module Async
260
269
  # @returns [Task] The task that was scheduled into the reactor.
261
270
  # @deprecated With no replacement.
262
271
  def async(*arguments, **options, &block)
272
+ Kernel::raise ClosedError if @selector.nil?
273
+
263
274
  task = Task.new(Task.current? || self, **options, &block)
264
275
 
265
276
  # I want to take a moment to explain the logic of this.
data/lib/async/task.rb CHANGED
@@ -59,6 +59,12 @@ module Async
59
59
  #
60
60
  # @public Since `stable-v1`.
61
61
  class Task < Node
62
+ class FinishedError < RuntimeError
63
+ def initialize(message = "Cannot create child task within a task that has finished execution!")
64
+ super
65
+ end
66
+ end
67
+
62
68
  # @deprecated With no replacement.
63
69
  def self.yield
64
70
  Fiber.scheduler.transfer
@@ -90,6 +96,22 @@ module Async
90
96
  @fiber&.backtrace(*arguments)
91
97
  end
92
98
 
99
+ def annotate(annotation, &block)
100
+ if @fiber
101
+ @fiber.annotate(annotation, &block)
102
+ else
103
+ super
104
+ end
105
+ end
106
+
107
+ def annotation
108
+ if @fiber
109
+ @fiber.annotation
110
+ else
111
+ super
112
+ end
113
+ end
114
+
93
115
  def to_s
94
116
  "\#<#{self.description} (#{@status})>"
95
117
  end
@@ -164,7 +186,7 @@ module Async
164
186
 
165
187
  # Run an asynchronous task as a child of the current task.
166
188
  def async(*arguments, **options, &block)
167
- raise "Cannot create child task within a task that has finished execution!" if self.finished?
189
+ raise FinishedError if self.finished?
168
190
 
169
191
  task = Task.new(self, **options, &block)
170
192
 
@@ -199,6 +221,10 @@ module Async
199
221
  attr :result
200
222
 
201
223
  # Stop the task and all of its children.
224
+ #
225
+ # If `later` is false, it means that `stop` has been invoked directly. When `later` is true, it means that `stop` is invoked by `stop_children` or some other indirect mechanism. In that case, if we encounter the "current" fiber, we can't stop it right away, as it's currently performing `#stop`. Stopping it immediately would interrupt the current stop traversal, so we need to schedule the stop to occur later.
226
+ #
227
+ # @parameter later [Boolean] Whether to stop the task later, or immediately.
202
228
  def stop(later = false)
203
229
  if self.stopped?
204
230
  # If we already stopped this task... don't try to stop it again:
@@ -208,6 +234,7 @@ module Async
208
234
  # If the fiber is alive, we need to stop it:
209
235
  if @fiber&.alive?
210
236
  if self.current?
237
+ # If the fiber is current, and later is `true`, we need to schedule the fiber to be stopped later, as it's currently invoking `stop`:
211
238
  if later
212
239
  # If the fiber is the current fiber and we want to stop it later, schedule it:
213
240
  Fiber.scheduler.push(Stop::Later.new(self))
@@ -218,6 +245,7 @@ module Async
218
245
  else
219
246
  # If the fiber is not curent, we can raise the exception directly:
220
247
  begin
248
+ # There is a chance that this will stop the fiber that originally called stop. If that happens, the exception handling in `#stopped` will rescue the exception and re-raise it later.
221
249
  Fiber.scheduler.raise(@fiber, Stop)
222
250
  rescue FiberError
223
251
  # In some cases, this can cause a FiberError (it might be resumed already), so we schedule it to be stopped later:
@@ -244,7 +272,7 @@ module Async
244
272
  end
245
273
 
246
274
  def current?
247
- self.equal?(Thread.current[:async_task])
275
+ Fiber.current.equal?(@fiber)
248
276
  end
249
277
 
250
278
  private
@@ -289,11 +317,23 @@ module Async
289
317
  end
290
318
 
291
319
  def stopped!
292
- # Console.logger.info(self, self.annotation) {"Task was stopped with #{@children&.size.inspect} children!"}
320
+ # Console.logger.info(self, status:) {"Task #{self} was stopped with #{@children&.size.inspect} children!"}
293
321
  @status = :stopped
294
322
 
295
- # We are not running, but children might be so we should stop them:
296
- stop_children(true)
323
+ stopped = false
324
+
325
+ begin
326
+ # We are bnot running, but children might be so we should stop them:
327
+ stop_children(true)
328
+ rescue Stop
329
+ stopped = true
330
+ # If we are stopping children, and one of them tries to stop the current task, we should ignore it. We will be stopped later.
331
+ retry
332
+ end
333
+
334
+ if stopped
335
+ raise Stop, "Stopping current task!"
336
+ end
297
337
  end
298
338
 
299
339
  def stop!
@@ -303,7 +343,7 @@ module Async
303
343
  end
304
344
 
305
345
  def schedule(&block)
306
- @fiber = Fiber.new do
346
+ @fiber = Fiber.new(annotation: self.annotation) do
307
347
  set!
308
348
 
309
349
  begin
data/lib/async/version.rb CHANGED
@@ -4,5 +4,5 @@
4
4
  # Copyright, 2017-2022, by Samuel Williams.
5
5
 
6
6
  module Async
7
- VERSION = "2.5.1"
7
+ VERSION = "2.6.0"
8
8
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.1
4
+ version: 2.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -56,7 +56,7 @@ cert_chain:
56
56
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
57
57
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
58
58
  -----END CERTIFICATE-----
59
- date: 2023-05-15 00:00:00.000000000 Z
59
+ date: 2023-06-07 00:00:00.000000000 Z
60
60
  dependencies:
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: console
@@ -100,6 +100,20 @@ dependencies:
100
100
  - - "~>"
101
101
  - !ruby/object:Gem::Version
102
102
  version: '4.1'
103
+ - !ruby/object:Gem::Dependency
104
+ name: fiber-annotation
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :runtime
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
103
117
  - !ruby/object:Gem::Dependency
104
118
  name: bake-test
105
119
  requirement: !ruby/object:Gem::Requirement
@@ -247,7 +261,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
247
261
  - !ruby/object:Gem::Version
248
262
  version: '0'
249
263
  requirements: []
250
- rubygems_version: 3.5.0.dev
264
+ rubygems_version: 3.4.7
251
265
  signing_key:
252
266
  specification_version: 4
253
267
  summary: A concurrency framework for Ruby.
metadata.gz.sig CHANGED
Binary file