Skip to content

Commit af8a7f3

Browse files
committed
Refine interface.
1 parent 09cb678 commit af8a7f3

4 files changed

Lines changed: 55 additions & 15 deletions

File tree

lib/async/scheduler.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ def with_timeout(duration, exception = TimeoutError, message = "execution expire
553553
if block.arity.zero?
554554
yield
555555
else
556-
yield Timeout.new(@timers, timer, duration)
556+
yield Timeout.new(@timers, timer)
557557
end
558558
ensure
559559
timer&.cancel!

lib/async/timeout.rb

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,33 @@ module Async
88
# @public Since *Async v2.24*.
99
class Timeout
1010
# Initialize a new timeout.
11-
def initialize(timers, handle, duration = nil)
11+
def initialize(timers, handle)
1212
@timers = timers
1313
@handle = handle
14-
@duration = duration || (handle.time - timers.now)
1514
end
1615

17-
# @attribute [Numeric] The duration of the timeout.
18-
attr :duration
16+
# @returns [Numeric] The time remaining until the timeout occurs.
17+
def duration
18+
@handle.time - @timers.now
19+
end
1920

2021
# Update the duration of the timeout, rescheduling it if necessary.
2122
#
22-
# The duration is relative to the time the timeout was created.
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.
2324
#
2425
# @parameter value [Numeric] The new duration to assign to the timeout.
2526
def duration=(value)
26-
delta = value - @duration
27-
self.reschedule(time + delta, value)
27+
self.reschedule(@timers.now + value)
2828
end
2929

3030
# Adjust the timeout by the specified duration, rescheduling it if necessary.
3131
#
32+
# The duration is relative to the timeout time, e.g. adjusting the timeout by 5 increases the current duration by 5 seconds.
33+
#
3234
# @parameter duration [Numeric] The duration to adjust the timeout by.
3335
# @returns [Numeric] The new time at which the timeout will occur.
3436
def adjust(duration)
35-
self.reschedule(time + duration, @duration + duration)
37+
self.reschedule(time + duration)
3638
end
3739

3840
# @returns [Numeric] The time at which the timeout will occur.
@@ -48,6 +50,11 @@ def time=(value)
4850
self.reschedule(value)
4951
end
5052

53+
# @returns [Numeric] The current time in the scheduler.
54+
def now
55+
@timers.now
56+
end
57+
5158
# Cancel the timeout.
5259
def cancel!
5360
@handle.cancel!
@@ -65,13 +72,11 @@ class CancelledError < RuntimeError
6572
# Reschedule the timeout to occur at the specified time.
6673
#
6774
# @parameter time [Numeric] The new time to schedule the timeout for.
68-
# @parameter duration [Numeric | Nil] The new duration to assign to the timeout.
6975
# @returns [Numeric] The new time at which the timeout will occur.
70-
private def reschedule(time, duration = nil)
76+
private def reschedule(time)
7177
if block = @handle&.block
7278
@handle.cancel!
7379

74-
@duration = duration || (time - @timers.now)
7580
@handle = @timers.schedule(time, block)
7681

7782
return time

releases.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,34 @@
55
- Ruby v3.1 support is dropped.
66
- `Async::Wrapper` which was previously deprecated, is now removed.
77

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+
836
## v2.23.0
937

1038
- Rename `ASYNC_SCHEDULER_DEFAULT_WORKER_POOL` to `ASYNC_SCHEDULER_WORKER_POOL`.

test/async/timeout.rb

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@
77
it "can schedule a timeout" do
88
scheduler.with_timeout(1) do |timeout|
99
expect(timeout.time).to be >= 0
10-
expect(timeout.duration).to be == 1
10+
expect(timeout.duration).to (be > 0).and(be <= 1)
1111
end
1212
end
1313

1414
with "#adjust" do
1515
it "can adjust the timeout" do
1616
scheduler.with_timeout(1) do |timeout|
1717
timeout.adjust(1)
18-
expect(timeout.duration).to be == 2
18+
expect(timeout.duration).to (be > 1).and(be <= 2)
1919
end
2020
end
2121
end
@@ -24,7 +24,14 @@
2424
it "can set the timeout duration" do
2525
scheduler.with_timeout(1) do |timeout|
2626
timeout.duration = 2
27-
expect(timeout.duration).to be == 2
27+
expect(timeout.duration).to (be > 1).and(be <= 2)
28+
end
29+
end
30+
31+
it "can increase the timeout duration" do
32+
scheduler.with_timeout(1) do |timeout|
33+
timeout.duration += 2
34+
expect(timeout.duration).to (be > 2).and(be <= 3)
2835
end
2936
end
3037
end

0 commit comments

Comments
 (0)