Wraps a `.Future` (or other yieldable object) in a timeout. Raises `tornado.util.TimeoutError` if the input future does not complete before ``timeout``, which may be specified in any form allowed by `.IOLoop.add_timeout` (i.e. a `datetime.timedelta` or an absolute time relative to `
(
timeout: Union[float, datetime.timedelta],
future: _Yieldable,
quiet_exceptions: "Union[Type[Exception], Tuple[Type[Exception], ...]]" = (),
)
| 590 | |
| 591 | |
| 592 | def with_timeout( |
| 593 | timeout: Union[float, datetime.timedelta], |
| 594 | future: _Yieldable, |
| 595 | quiet_exceptions: "Union[Type[Exception], Tuple[Type[Exception], ...]]" = (), |
| 596 | ) -> Future: |
| 597 | """Wraps a `.Future` (or other yieldable object) in a timeout. |
| 598 | |
| 599 | Raises `tornado.util.TimeoutError` if the input future does not |
| 600 | complete before ``timeout``, which may be specified in any form |
| 601 | allowed by `.IOLoop.add_timeout` (i.e. a `datetime.timedelta` or |
| 602 | an absolute time relative to `.IOLoop.time`) |
| 603 | |
| 604 | If the wrapped `.Future` fails after it has timed out, the exception |
| 605 | will be logged unless it is either of a type contained in |
| 606 | ``quiet_exceptions`` (which may be an exception type or a sequence of |
| 607 | types), or an ``asyncio.CancelledError``. |
| 608 | |
| 609 | The wrapped `.Future` is not canceled when the timeout expires, |
| 610 | permitting it to be reused. `asyncio.wait_for` is similar to this |
| 611 | function but it does cancel the wrapped `.Future` on timeout. |
| 612 | |
| 613 | .. versionadded:: 4.0 |
| 614 | |
| 615 | .. versionchanged:: 4.1 |
| 616 | Added the ``quiet_exceptions`` argument and the logging of unhandled |
| 617 | exceptions. |
| 618 | |
| 619 | .. versionchanged:: 4.4 |
| 620 | Added support for yieldable objects other than `.Future`. |
| 621 | |
| 622 | .. versionchanged:: 6.0.3 |
| 623 | ``asyncio.CancelledError`` is now always considered "quiet". |
| 624 | |
| 625 | .. versionchanged:: 6.2 |
| 626 | ``tornado.util.TimeoutError`` is now an alias to ``asyncio.TimeoutError``. |
| 627 | |
| 628 | """ |
| 629 | # It's tempting to optimize this by cancelling the input future on timeout |
| 630 | # instead of creating a new one, but A) we can't know if we are the only |
| 631 | # one waiting on the input future, so cancelling it might disrupt other |
| 632 | # callers and B) concurrent futures can only be cancelled while they are |
| 633 | # in the queue, so cancellation cannot reliably bound our waiting time. |
| 634 | future_converted = convert_yielded(future) |
| 635 | result = _create_future() |
| 636 | chain_future(future_converted, result) |
| 637 | io_loop = IOLoop.current() |
| 638 | |
| 639 | def error_callback(future: Future) -> None: |
| 640 | try: |
| 641 | future.result() |
| 642 | except asyncio.CancelledError: |
| 643 | pass |
| 644 | except Exception as e: |
| 645 | if not isinstance(e, quiet_exceptions): |
| 646 | app_log.error( |
| 647 | "Exception in Future %r after timeout", future, exc_info=True |
| 648 | ) |
| 649 |
nothing calls this directly
no test coverage detected