async 2.44.0 → 2.45.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: b7ec9caa7a2e151195fa3da29d96fb2fe0f02399b89d17d93eeb7507667596ad
4
- data.tar.gz: ed1548c91c789ef1ffbc268a1470cde4f1d1dc1ffed12678825e1d253b0a8d67
3
+ metadata.gz: 3d9408068579f9a742c20019cf9024bbc4c545c239c4c5178e929c377ac06b6c
4
+ data.tar.gz: 699c17d5dbff6502e1611252982c3595b7b84d57284010222462b838e683d1ac
5
5
  SHA512:
6
- metadata.gz: d8cc76cc2cc6f3a19ce94383b4123e83b9274a3431b9dc2fc71bfff62946ef3dbad0b4c8f4c607b3071d219b5efc73315d589b10e4467c26e60bbd48eb2c6103
7
- data.tar.gz: b914c7f81337ce52ae1aadb42b43f0d702c94847ae0052d326ee510a57c87517b957b5c0fd70988d9b08d4d9f061348b93dceaaf194b3d19ab809eb45c0387f7
6
+ metadata.gz: a40ca6a441ad341267c5782d089d512b45b36765afbdd1c6382ebb7f931e273cdf29d08ae3a446a0b624618981730c2ee69e15d39adb0956dc44fc1d2ccd2ab9
7
+ data.tar.gz: 325d951d894d7c2fb9cc042534e5e8d76c3edbeb81c061993204ef345af499cfd0fd71ebaae0a6fbbdfd62afdf99a859564554c9cb97dcd730111385948aebf1
checksums.yaml.gz.sig CHANGED
Binary file
@@ -74,6 +74,42 @@ end
74
74
  puts "The number was: #{task.wait}"
75
75
  ```
76
76
 
77
+ ### Comparing `Async` and `Sync`
78
+
79
+ If you are familiar with JavaScript's `async`/`await`, `Async{...}` is similar to calling an asynchronous function: it starts the work and returns a promise-like {ruby Async::Task} that you can wait on later.
80
+
81
+ ```ruby
82
+ task = Async do
83
+ bar
84
+ end
85
+
86
+ task.wait # Returns the value of bar.
87
+ ```
88
+
89
+ This is similar to JavaScript code that keeps the promise:
90
+
91
+ ```javascript
92
+ const promise = bar();
93
+
94
+ await promise; // Returns the value of bar.
95
+ ```
96
+
97
+ `Sync{...}` is similar to immediately awaiting that work: it runs the block in an event loop and returns the block's value directly.
98
+
99
+ ```ruby
100
+ result = Sync do
101
+ bar
102
+ end
103
+ ```
104
+
105
+ This is similar to:
106
+
107
+ ```javascript
108
+ const result = await bar();
109
+ ```
110
+
111
+ The main difference is that JavaScript starts with an event loop already available, while Ruby code needs one to be provided by a fiber scheduler. `Sync{...}` is the usual way to create or reuse that event loop when the caller wants a direct return value instead of a task.
112
+
77
113
  ## Creating a Fiber Scheduler
78
114
 
79
115
  The first (top level) async block will also create an instance of {ruby Async::Reactor} which is a subclass of {ruby Async::Scheduler} to handle the event loop. You can also do this directly using {ruby Fiber.set_scheduler}:
data/context/index.yaml CHANGED
@@ -3,6 +3,8 @@
3
3
  ---
4
4
  description: A concurrency framework for Ruby.
5
5
  metadata:
6
+ bug_tracker_uri: https://github.com/socketry/async/issues
7
+ changelog_uri: https://github.com/socketry/async/blob/main/releases.md
6
8
  documentation_uri: https://socketry.github.io/async/
7
9
  funding_uri: https://github.com/sponsors/ioquatix/
8
10
  source_code_uri: https://github.com/socketry/async.git
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2017-2025, by Samuel Williams.
4
+ # Copyright, 2017-2026, by Samuel Williams.
5
5
  # Copyright, 2017, by Kent Gruber.
6
6
  # Copyright, 2026, by Robert Mosolgo.
7
7
 
@@ -309,10 +309,12 @@ module Async
309
309
  # @parameter timeout [Float | Nil] The maximum time to wait, or if nil, indefinitely.
310
310
  def io_wait(io, events, timeout = nil)
311
311
  fiber = Fiber.current
312
+ expired = false
312
313
 
313
314
  if timeout
314
315
  # If an explicit timeout is specified, we expect that the user will handle it themselves:
315
316
  timer = @timers.after(timeout) do
317
+ expired = true
316
318
  fiber.transfer
317
319
  end
318
320
  elsif timeout = io.timeout
@@ -322,7 +324,13 @@ module Async
322
324
  end
323
325
  end
324
326
 
325
- return @selector.io_wait(fiber, io, events)
327
+ # A selector wait may return a falsy result when the fiber is resumed without the requested IO becoming ready. For example, a deferred unblock from a previous blocking operation may arrive after the fiber has moved on to this wait. Retry these stale or spurious wake-ups without resetting the original timer.
328
+ until result = @selector.io_wait(fiber, io, events)
329
+ # If the original timer resumed the fiber, the falsy result represents the timeout rather than a spurious wake-up:
330
+ return nil if expired
331
+ end
332
+
333
+ return result
326
334
  ensure
327
335
  timer&.cancel!
328
336
  end
@@ -415,7 +423,14 @@ module Async
415
423
  # @returns [Process::Status] A process status instance.
416
424
  # @asynchronous May be non-blocking..
417
425
  def process_wait(pid, flags)
418
- return @selector.process_wait(Fiber.current, pid, flags)
426
+ fiber = Fiber.current
427
+
428
+ # A native process wait may be interrupted before the child exits. io-event reports this as `false` and leaves the retry policy to the scheduler. Retry only `false`, since `nil` is a legitimate result for `Process::WNOHANG`.
429
+ while true
430
+ status = @selector.process_wait(fiber, pid, flags)
431
+
432
+ return status unless status == false
433
+ end
419
434
  end
420
435
 
421
436
  # Wait for the specified IOs to become ready for the specified events.
data/lib/async/version.rb CHANGED
@@ -5,5 +5,5 @@
5
5
 
6
6
  # @namespace
7
7
  module Async
8
- VERSION = "2.44.0"
8
+ VERSION = "2.45.0"
9
9
  end
data/lib/kernel/async.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2024, by Samuel Williams.
4
+ # Copyright, 2019-2026, by Samuel Williams.
5
5
  # Copyright, 2026, by Shopify Inc.
6
6
 
7
7
  require_relative "../async/reactor"
data/lib/kernel/sync.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2025, by Samuel Williams.
4
+ # Copyright, 2019-2026, by Samuel Williams.
5
5
  # Copyright, 2020, by Brian Morearty.
6
6
  # Copyright, 2024, by Patrik Wenger.
7
7
  # Copyright, 2025-2026, by Shopify Inc.
data/readme.md CHANGED
@@ -35,6 +35,10 @@ Please see the [project documentation](https://socketry.github.io/async/) for mo
35
35
 
36
36
  Please see the [project releases](https://socketry.github.io/async/releases/index) for all releases.
37
37
 
38
+ ### v2.45.0
39
+
40
+ - Fixed scheduler I/O and process waits returning prematurely after stale or interrupted wake-ups. I/O waits now preserve their original timeout, while blocking process waits retry and non-blocking `Process::WNOHANG` waits still return `nil`.
41
+
38
42
  ### v2.44.0
39
43
 
40
44
  - Fixed scheduler cleanup after forking while other fibers are blocked.
@@ -73,11 +77,6 @@ Please see the [project releases](https://socketry.github.io/async/releases/inde
73
77
  - Introduce `Async::Loop` for robust, time-aligned loops.
74
78
  - Add support for `Async::Promise#wait(timeout: N)`.
75
79
 
76
- ### v2.36.0
77
-
78
- - Introduce `Task#wait_all` which recursively waits for all children and self, excepting the current task.
79
- - Introduce `Task#join` as an alias for `Task#wait` for compatibility with `Thread#join` and similar interfaces.
80
-
81
80
  ## See Also
82
81
 
83
82
  - [async-http](https://github.com/socketry/async-http) — Asynchronous HTTP client/server.
data/releases.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Releases
2
2
 
3
+ ## v2.45.0
4
+
5
+ - Fixed scheduler I/O and process waits returning prematurely after stale or interrupted wake-ups. I/O waits now preserve their original timeout, while blocking process waits retry and non-blocking `Process::WNOHANG` waits still return `nil`.
6
+
3
7
  ## v2.44.0
4
8
 
5
9
  - Fixed scheduler cleanup after forking while other fibers are blocked.
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.44.0
4
+ version: 2.45.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -109,14 +109,14 @@ dependencies:
109
109
  requirements:
110
110
  - - "~>"
111
111
  - !ruby/object:Gem::Version
112
- version: '1.11'
112
+ version: '1.21'
113
113
  type: :runtime
114
114
  prerelease: false
115
115
  version_requirements: !ruby/object:Gem::Requirement
116
116
  requirements:
117
117
  - - "~>"
118
118
  - !ruby/object:Gem::Version
119
- version: '1.11'
119
+ version: '1.21'
120
120
  executables: []
121
121
  extensions: []
122
122
  extra_rdoc_files: []
@@ -173,6 +173,8 @@ homepage: https://github.com/socketry/async
173
173
  licenses:
174
174
  - MIT
175
175
  metadata:
176
+ bug_tracker_uri: https://github.com/socketry/async/issues
177
+ changelog_uri: https://github.com/socketry/async/blob/main/releases.md
176
178
  documentation_uri: https://socketry.github.io/async/
177
179
  funding_uri: https://github.com/sponsors/ioquatix/
178
180
  source_code_uri: https://github.com/socketry/async.git
metadata.gz.sig CHANGED
Binary file