Skip to content

Commit

Permalink
improve error message when run_sync does not complete for reasons oth…
Browse files Browse the repository at this point in the history
…er than timeout

keeps TimeoutError for maximum compatibility, but e.g. RuntimeError or other might be appropriate
  • Loading branch information
minrk committed Oct 28, 2024
1 parent 385fd88 commit 7eaf007
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 2 deletions.
12 changes: 10 additions & 2 deletions tornado/ioloop.py
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ async def main():
.. versionchanged:: 6.2
``tornado.util.TimeoutError`` is now an alias to ``asyncio.TimeoutError``.
"""
future_cell = [None] # type: List[Optional[Future]]
future_cell = [None, False] # type: List[Optional[Future], bool]

def run() -> None:
try:
Expand All @@ -518,6 +518,8 @@ def run() -> None:
if timeout is not None:

def timeout_callback() -> None:
# signal that timeout is triggered
future_cell[1] = True
# If we can cancel the future, do so and wait on it. If not,
# Just stop the loop and return with the task still pending.
# (If we neither cancel nor wait for the task, a warning
Expand All @@ -532,7 +534,13 @@ def timeout_callback() -> None:
self.remove_timeout(timeout_handle)
assert future_cell[0] is not None
if future_cell[0].cancelled() or not future_cell[0].done():
raise TimeoutError("Operation timed out after %s seconds" % timeout)
if future_cell[1]:
msg = "Operation timed out after %s seconds" % timeout
else:
# timeout not called; maybe stop() was called explicitly
# or some other cancellation
msg = "Operation cancelled"
raise TimeoutError(msg)
return future_cell[0].result()

def time(self) -> float:
Expand Down
10 changes: 10 additions & 0 deletions tornado/test/ioloop_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,16 @@ async def f2():

self.io_loop.run_sync(f2)

def test_stop_no_timeout(self):
async def f():
await asyncio.sleep(0.1)
IOLoop.current().stop()
await asyncio.sleep(10)

with self.assertRaises(TimeoutError) as cm:
self.io_loop.run_sync(f)
assert "Operation cancelled" in str(cm.exception)


class TestPeriodicCallbackMath(unittest.TestCase):
def simulate_calls(self, pc, durations):
Expand Down

0 comments on commit 7eaf007

Please sign in to comment.