async 2.23.1 → 2.24.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
- checksums.yaml.gz.sig +0 -0
- data/lib/async/scheduler.rb +11 -16
- data/lib/async/timeout.rb +88 -0
- data/lib/async/version.rb +1 -1
- data/lib/async/worker_pool.rb +1 -1
- data/readme.md +6 -0
- data/releases.md +33 -0
- data.tar.gz.sig +0 -0
- metadata +3 -3
- metadata.gz.sig +0 -0
- data/lib/async/wrapper.rb +0 -67
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 95c1315007ff80d78bdd1538d2b2963ed951db5aa92906ea6f22560612540cbc
|
4
|
+
data.tar.gz: 03ffadcf7c2523827bd6c49340df0a846f8ab3214593d897b4359b548a765cef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 62c15e0c19e7f3277ca9e4981b0304d5f039367fb0d6b996a8c562be170b3436f66e97f33fcfd5eb0ed8ec84e760ae2b565a022604e026f3b2c797613534fd59
|
7
|
+
data.tar.gz: 79c7148d35f3e06243b3845721b8a1ebcf5fd2e6244eab18ac5a0f42894088334df307c4da52d9d9c59b0d9499e457f0990022d570abf109202416cf168211a1
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/lib/async/scheduler.rb
CHANGED
@@ -7,6 +7,7 @@
|
|
7
7
|
|
8
8
|
require_relative "clock"
|
9
9
|
require_relative "task"
|
10
|
+
require_relative "timeout"
|
10
11
|
require_relative "worker_pool"
|
11
12
|
|
12
13
|
require "io/event"
|
@@ -269,16 +270,6 @@ module Async
|
|
269
270
|
::Resolv.getaddresses(hostname)
|
270
271
|
end
|
271
272
|
|
272
|
-
if IO.method_defined?(:timeout)
|
273
|
-
private def get_timeout(io)
|
274
|
-
io.timeout
|
275
|
-
end
|
276
|
-
else
|
277
|
-
private def get_timeout(io)
|
278
|
-
nil
|
279
|
-
end
|
280
|
-
end
|
281
|
-
|
282
273
|
# Wait for the specified IO to become ready for the specified events.
|
283
274
|
#
|
284
275
|
# @public Since *Async v2*.
|
@@ -295,7 +286,7 @@ module Async
|
|
295
286
|
timer = @timers.after(timeout) do
|
296
287
|
fiber.transfer
|
297
288
|
end
|
298
|
-
elsif timeout =
|
289
|
+
elsif timeout = io.timeout
|
299
290
|
# Otherwise, if we default to the io's timeout, we raise an exception:
|
300
291
|
timer = @timers.after(timeout) do
|
301
292
|
fiber.raise(::IO::TimeoutError, "Timeout (#{timeout}s) while waiting for IO to become ready!")
|
@@ -320,7 +311,7 @@ module Async
|
|
320
311
|
def io_read(io, buffer, length, offset = 0)
|
321
312
|
fiber = Fiber.current
|
322
313
|
|
323
|
-
if timeout =
|
314
|
+
if timeout = io.timeout
|
324
315
|
timer = @timers.after(timeout) do
|
325
316
|
fiber.raise(::IO::TimeoutError, "Timeout (#{timeout}s) while waiting for IO to become readable!")
|
326
317
|
end
|
@@ -344,7 +335,7 @@ module Async
|
|
344
335
|
def io_write(io, buffer, length, offset = 0)
|
345
336
|
fiber = Fiber.current
|
346
337
|
|
347
|
-
if timeout =
|
338
|
+
if timeout = io.timeout
|
348
339
|
timer = @timers.after(timeout) do
|
349
340
|
fiber.raise(::IO::TimeoutError, "Timeout (#{timeout}s) while waiting for IO to become writable!")
|
350
341
|
end
|
@@ -549,7 +540,7 @@ module Async
|
|
549
540
|
# @parameter duration [Numeric] The time in seconds, in which the task should complete.
|
550
541
|
# @parameter exception [Class] The exception class to raise.
|
551
542
|
# @parameter message [String] The message to pass to the exception.
|
552
|
-
# @yields {|
|
543
|
+
# @yields {|timeout| ...} The block to execute with a timeout.
|
553
544
|
def with_timeout(duration, exception = TimeoutError, message = "execution expired", &block)
|
554
545
|
fiber = Fiber.current
|
555
546
|
|
@@ -559,7 +550,11 @@ module Async
|
|
559
550
|
end
|
560
551
|
end
|
561
552
|
|
562
|
-
|
553
|
+
if block.arity.zero?
|
554
|
+
yield
|
555
|
+
else
|
556
|
+
yield Timeout.new(@timers, timer)
|
557
|
+
end
|
563
558
|
ensure
|
564
559
|
timer&.cancel!
|
565
560
|
end
|
@@ -574,7 +569,7 @@ module Async
|
|
574
569
|
# @parameter message [String] The message to pass to the exception.
|
575
570
|
# @yields {|duration| ...} The block to execute with a timeout.
|
576
571
|
def timeout_after(duration, exception, message, &block)
|
577
|
-
with_timeout(duration, exception, message) do
|
572
|
+
with_timeout(duration, exception, message) do
|
578
573
|
yield duration
|
579
574
|
end
|
580
575
|
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2025, by Samuel Williams.
|
5
|
+
|
6
|
+
module Async
|
7
|
+
# Represents a flexible timeout that can be rescheduled or extended.
|
8
|
+
# @public Since *Async v2.24*.
|
9
|
+
class Timeout
|
10
|
+
# Initialize a new timeout.
|
11
|
+
def initialize(timers, handle)
|
12
|
+
@timers = timers
|
13
|
+
@handle = handle
|
14
|
+
end
|
15
|
+
|
16
|
+
# @returns [Numeric] The time remaining until the timeout occurs, in seconds.
|
17
|
+
def duration
|
18
|
+
@handle.time - @timers.now
|
19
|
+
end
|
20
|
+
|
21
|
+
# Update the duration of the timeout.
|
22
|
+
#
|
23
|
+
# The duration is relative to the current time, e.g. setting the duration to 5 means the timeout will occur in 5 seconds from now.
|
24
|
+
#
|
25
|
+
# @parameter value [Numeric] The new duration to assign to the timeout, in seconds.
|
26
|
+
def duration=(value)
|
27
|
+
self.reschedule(@timers.now + value)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Adjust the timeout by the specified duration.
|
31
|
+
#
|
32
|
+
# The duration is relative to the timeout time, e.g. adjusting the timeout by 5 increases the current duration by 5 seconds.
|
33
|
+
#
|
34
|
+
# @parameter duration [Numeric] The duration to adjust the timeout by, in seconds.
|
35
|
+
# @returns [Numeric] The new time at which the timeout will occur.
|
36
|
+
def adjust(duration)
|
37
|
+
self.reschedule(time + duration)
|
38
|
+
end
|
39
|
+
|
40
|
+
# @returns [Numeric] The time at which the timeout will occur, in seconds since {now}.
|
41
|
+
def time
|
42
|
+
@handle.time
|
43
|
+
end
|
44
|
+
|
45
|
+
# Assign a new time to the timeout, rescheduling it if necessary.
|
46
|
+
#
|
47
|
+
# @parameter value [Numeric] The new time to assign to the timeout.
|
48
|
+
# @returns [Numeric] The new time at which the timeout will occur.
|
49
|
+
def time=(value)
|
50
|
+
self.reschedule(value)
|
51
|
+
end
|
52
|
+
|
53
|
+
# @returns [Numeric] The current time in the scheduler, relative to the time of this timeout, in seconds.
|
54
|
+
def now
|
55
|
+
@timers.now
|
56
|
+
end
|
57
|
+
|
58
|
+
# Cancel the timeout, preventing it from executing.
|
59
|
+
def cancel!
|
60
|
+
@handle.cancel!
|
61
|
+
end
|
62
|
+
|
63
|
+
# @returns [Boolean] Whether the timeout has been cancelled.
|
64
|
+
def cancelled?
|
65
|
+
@handle.cancelled?
|
66
|
+
end
|
67
|
+
|
68
|
+
# Raised when attempting to reschedule a cancelled timeout.
|
69
|
+
class CancelledError < RuntimeError
|
70
|
+
end
|
71
|
+
|
72
|
+
# Reschedule the timeout to occur at the specified time.
|
73
|
+
#
|
74
|
+
# @parameter time [Numeric] The new time to schedule the timeout for.
|
75
|
+
# @returns [Numeric] The new time at which the timeout will occur.
|
76
|
+
private def reschedule(time)
|
77
|
+
if block = @handle&.block
|
78
|
+
@handle.cancel!
|
79
|
+
|
80
|
+
@handle = @timers.schedule(time, block)
|
81
|
+
|
82
|
+
return time
|
83
|
+
else
|
84
|
+
raise CancelledError, "Cannot reschedule a cancelled timeout!"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/async/version.rb
CHANGED
data/lib/async/worker_pool.rb
CHANGED
@@ -14,7 +14,7 @@ module Async
|
|
14
14
|
module BlockingOperationWait
|
15
15
|
# Wait for the given work to be executed.
|
16
16
|
#
|
17
|
-
# @public Since *Async v2.
|
17
|
+
# @public Since *Async v2.21* and *Ruby v3.4*.
|
18
18
|
# @asynchronous May be non-blocking.
|
19
19
|
#
|
20
20
|
# @parameter work [Proc] The work to execute on a background thread.
|
data/readme.md
CHANGED
@@ -35,6 +35,12 @@ 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.24.0
|
39
|
+
|
40
|
+
- Ruby v3.1 support is dropped.
|
41
|
+
- `Async::Wrapper` which was previously deprecated, is now removed.
|
42
|
+
- [Flexible Timeouts](https://socketry.github.io/async/releases/index#flexible-timeouts)
|
43
|
+
|
38
44
|
### v2.23.0
|
39
45
|
|
40
46
|
- Rename `ASYNC_SCHEDULER_DEFAULT_WORKER_POOL` to `ASYNC_SCHEDULER_WORKER_POOL`.
|
data/releases.md
CHANGED
@@ -1,5 +1,38 @@
|
|
1
1
|
# Releases
|
2
2
|
|
3
|
+
## v2.24.0
|
4
|
+
|
5
|
+
- Ruby v3.1 support is dropped.
|
6
|
+
- `Async::Wrapper` which was previously deprecated, is now removed.
|
7
|
+
|
8
|
+
### Flexible Timeouts
|
9
|
+
|
10
|
+
When {ruby Async::Scheduler\#with\_timeout} is invoked with a block, it can receive a {ruby Async::Timeout} instance. This allows you to adjust or cancel the timeout while the block is executing. This is useful for long-running tasks that may need to adjust their timeout based on external factors.
|
11
|
+
|
12
|
+
``` ruby
|
13
|
+
Async do
|
14
|
+
Async::Scheduler.with_timeout(5) do |timeout|
|
15
|
+
# Do some work that may take a while...
|
16
|
+
|
17
|
+
if some_condition
|
18
|
+
timeout.cancel! # Cancel the timeout
|
19
|
+
else
|
20
|
+
# Add 10 seconds to the current timeout:
|
21
|
+
timeout.adjust(10)
|
22
|
+
|
23
|
+
# Reduce the timeout by 10 seconds:
|
24
|
+
timeout.adjust(-10)
|
25
|
+
|
26
|
+
# Set the timeout to 10 seconds from now:
|
27
|
+
timeout.duration = 10
|
28
|
+
|
29
|
+
# Increase the current duration:
|
30
|
+
timeout.duration += 10
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
3
36
|
## v2.23.0
|
4
37
|
|
5
38
|
- Rename `ASYNC_SCHEDULER_DEFAULT_WORKER_POOL` to `ASYNC_SCHEDULER_WORKER_POOL`.
|
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.
|
4
|
+
version: 2.24.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
@@ -62,7 +62,7 @@ cert_chain:
|
|
62
62
|
Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
|
63
63
|
voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
|
64
64
|
-----END CERTIFICATE-----
|
65
|
-
date: 2025-03
|
65
|
+
date: 2025-05-03 00:00:00.000000000 Z
|
66
66
|
dependencies:
|
67
67
|
- !ruby/object:Gem::Dependency
|
68
68
|
name: console
|
@@ -157,12 +157,12 @@ files:
|
|
157
157
|
- lib/async/semaphore.rb
|
158
158
|
- lib/async/task.md
|
159
159
|
- lib/async/task.rb
|
160
|
+
- lib/async/timeout.rb
|
160
161
|
- lib/async/variable.rb
|
161
162
|
- lib/async/version.rb
|
162
163
|
- lib/async/waiter.md
|
163
164
|
- lib/async/waiter.rb
|
164
165
|
- lib/async/worker_pool.rb
|
165
|
-
- lib/async/wrapper.rb
|
166
166
|
- lib/kernel/async.rb
|
167
167
|
- lib/kernel/sync.rb
|
168
168
|
- lib/metrics/provider/async.rb
|
metadata.gz.sig
CHANGED
Binary file
|
data/lib/async/wrapper.rb
DELETED
@@ -1,67 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Released under the MIT License.
|
4
|
-
# Copyright, 2017-2024, by Samuel Williams.
|
5
|
-
# Copyright, 2017, by Kent Gruber.
|
6
|
-
|
7
|
-
warn "Async::Wrapper is deprecated and will be removed on 2025-03-31. Please use native interfaces instead.", uplevel: 1, category: :deprecated
|
8
|
-
|
9
|
-
module Async
|
10
|
-
# Represents an asynchronous IO within a reactor.
|
11
|
-
# @deprecated With no replacement. Prefer native interfaces.
|
12
|
-
class Wrapper
|
13
|
-
# An exception that occurs when the asynchronous operation was cancelled.
|
14
|
-
class Cancelled < StandardError
|
15
|
-
end
|
16
|
-
|
17
|
-
# @parameter io the native object to wrap.
|
18
|
-
# @parameter reactor [Reactor] the reactor that is managing this wrapper, or not specified, it's looked up by way of {Task.current}.
|
19
|
-
def initialize(io, reactor = nil)
|
20
|
-
@io = io
|
21
|
-
@reactor = reactor
|
22
|
-
|
23
|
-
@timeout = nil
|
24
|
-
end
|
25
|
-
|
26
|
-
attr_accessor :reactor
|
27
|
-
|
28
|
-
# Dup the underlying IO.
|
29
|
-
def dup
|
30
|
-
self.class.new(@io.dup)
|
31
|
-
end
|
32
|
-
|
33
|
-
# The underlying native `io`.
|
34
|
-
attr :io
|
35
|
-
|
36
|
-
# Wait for the io to become readable.
|
37
|
-
def wait_readable(timeout = @timeout)
|
38
|
-
@io.to_io.wait_readable(timeout) or raise TimeoutError
|
39
|
-
end
|
40
|
-
|
41
|
-
# Wait for the io to become writable.
|
42
|
-
def wait_priority(timeout = @timeout)
|
43
|
-
@io.to_io.wait_priority(timeout) or raise TimeoutError
|
44
|
-
end
|
45
|
-
|
46
|
-
# Wait for the io to become writable.
|
47
|
-
def wait_writable(timeout = @timeout)
|
48
|
-
@io.to_io.wait_writable(timeout) or raise TimeoutError
|
49
|
-
end
|
50
|
-
|
51
|
-
# Wait fo the io to become either readable or writable.
|
52
|
-
# @parameter duration [Float] timeout after the given duration if not `nil`.
|
53
|
-
def wait_any(timeout = @timeout)
|
54
|
-
@io.to_io.wait(::IO::READABLE|::IO::WRITABLE|::IO::PRIORITY, timeout) or raise TimeoutError
|
55
|
-
end
|
56
|
-
|
57
|
-
# Close the underlying IO.
|
58
|
-
def close
|
59
|
-
@io.close
|
60
|
-
end
|
61
|
-
|
62
|
-
# Whether the underlying IO is closed.
|
63
|
-
def closed?
|
64
|
-
@io.closed?
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|