Skip to content

Commit

Permalink
Add support for float timeouts using alarms (#8737)
Browse files Browse the repository at this point in the history
  • Loading branch information
zanieb authored Mar 7, 2023
1 parent a8fac67 commit 9cee961
Show file tree
Hide file tree
Showing 3 changed files with 11 additions and 15 deletions.
9 changes: 5 additions & 4 deletions src/prefect/_internal/concurrency/timeouts.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import contextlib
import ctypes
import math
import signal
import sys
import threading
Expand Down Expand Up @@ -228,12 +227,14 @@ def raise_alarm_as_timeout(signum, frame):
)
raise TimeoutError()

signal.signal(signal.SIGALRM, raise_alarm_as_timeout)
# Use `setitimer` instead of `signal.alarm` for float support; raises a SIGALRM
previous = signal.setitimer(signal.ITIMER_REAL, timeout)
try:
signal.signal(signal.SIGALRM, raise_alarm_as_timeout)
signal.alarm(math.ceil(timeout)) # alarms do not support floats
yield ctx
finally:
signal.alarm(0) # Clear the alarm when the context exits
# Clear the alarm when the context exits
signal.setitimer(signal.ITIMER_REAL, *previous)


@contextlib.contextmanager
Expand Down
12 changes: 4 additions & 8 deletions tests/_internal/concurrency/test_timeouts.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,11 @@ def test_cancel_sync_after_in_main_thread():
t0 = time.perf_counter()
with pytest.raises(TimeoutError):
with cancel_sync_after(0.1) as ctx:
# floats are not suppported by alarm timeouts so this will actually timeout
# after 1s
time.sleep(2)
time.sleep(1)
t1 = time.perf_counter()

assert ctx.cancelled()
assert t1 - t0 < 2
assert t1 - t0 < 1


def test_cancel_sync_after_in_worker_thread():
Expand Down Expand Up @@ -109,10 +107,8 @@ def test_cancel_sync_at():
t0 = time.perf_counter()
with pytest.raises(TimeoutError):
with cancel_sync_at(get_deadline(timeout=0.1)) as ctx:
# floats are not suppported by alarm timeouts so this will actually timeout
# after 1s
time.sleep(2)
time.sleep(1)
t1 = time.perf_counter()

assert ctx.cancelled()
assert t1 - t0 < 2
assert t1 - t0 < 1
5 changes: 2 additions & 3 deletions tests/_internal/concurrency/test_waiters.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def test_sync_waiter_timeout_in_main_thread():
with WorkerThread(run_once=True) as portal:

def on_worker_thread():
callback = Call.new(time.sleep, 2)
callback = Call.new(time.sleep, 1)
call.add_callback(callback)
return callback

Expand All @@ -93,8 +93,7 @@ def on_worker_thread():
with pytest.raises(TimeoutError):
callback.result()

# main thread timeouts round up to the nearest second
assert t1 - t0 < 2
assert t1 - t0 < 1

assert callback.cancelled()
assert not call.cancelled()
Expand Down

0 comments on commit 9cee961

Please sign in to comment.